如何在基类构造函数中使用派生类成员 所以,我是一个C++新手,所以让我解释一下我的问题,我是如何理解的,如果我错了请纠正我。
我有一个表示ui按钮的基类。它有如何在基类构造函数中使用派生类成员 所以,我是一个C++新手,所以让我解释一下我的问题,我是如何理解的,如果我错了请纠正我。,c++,oop,inheritance,C++,Oop,Inheritance,我有一个表示ui按钮的基类。它有onClick、mouseOver等方法和label等成员。此外,它还有一个rect成员,其中的“矩形”数据表示按钮:按钮在窗口中的x和y位置及其宽度和高度 简化代码: #include <cstdio> struct Rect { int x { 0 }; int y { 0 }; int w { 0 }; int h { 0 }; }; class BaseButton { protected: const int w
onClick
、mouseOver
等方法和label
等成员。此外,它还有一个rect
成员,其中的“矩形”数据表示按钮:按钮在窗口中的x和y位置及其宽度和高度
简化代码:
#include <cstdio>
struct Rect {
int x { 0 };
int y { 0 };
int w { 0 };
int h { 0 };
};
class BaseButton {
protected:
const int width { 0 };
const int height { 0 };
Rect rect;
public:
BaseButton(int x, int y) {
rect = Rect { x, y, width, height };
}
void debugRect () {
printf("x: %d, y: %d, w: %d, h: %d\n", rect.x, rect.y, rect.w, rect.h);
}
};
如果我调试它,结果如下:
int main () {
CheckboxButton cbb { 10, 10 };
cbb.debugRect(); // x: 10, y: 10, w: 0, h: 0
}
与其他一些OOP语言不同的是,基类构造函数无法访问派生类变量。例如,在python中,代码如下所示:
class Rect:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
class BaseButton:
width = 0
height = 0
def __init__(self, x, y):
self.rect = Rect(x, y, self.width, self.height)
def debug_rect(self):
print "x: {0}, y: {1}, w: {2}, h: {3}".format(self.rect.x, self.rect.y, self.rect.w, self.rect.h)
class CheckboxButton(BaseButton):
width = 16
height = 16
class SendButton(BaseButton):
width = 32
height = 16
cbb = CheckboxButton(10, 10)
cbb.debug_rect() # x: 10, y: 10, w: 16, h: 16
class BaseButton {
Rect rect;
public:
BaseButton(int x, int y, int w, int h) {
rect = Rect { x, y, w, h };
}
void debug_rect () {
printf("x: %d, y: %d, w: %d, h: %d\n", rect.x, rect.y, rect.w, rect.h);
}
};
class CheckboxButton: public BaseButton {
private:
using BaseButton::BaseButton;
protected:
public:
CheckboxButton(int x, int y): BaseButton { x, y, 16, 16 } {};
};
int main () {
CheckboxButton cbb { 10, 10 };
cbb.debug_rect();
}
我希望尽可能地重用基类构造函数的代码。因此,基本上,“配置”派生类参数,并让构造函数代码使用它们来生成每种类型按钮的实例
我能想到的一个解决方案是让基类构造函数接受它需要的所有参数,并使用固定参数从派生类重载此类构造函数,如下所示:
class Rect:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
class BaseButton:
width = 0
height = 0
def __init__(self, x, y):
self.rect = Rect(x, y, self.width, self.height)
def debug_rect(self):
print "x: {0}, y: {1}, w: {2}, h: {3}".format(self.rect.x, self.rect.y, self.rect.w, self.rect.h)
class CheckboxButton(BaseButton):
width = 16
height = 16
class SendButton(BaseButton):
width = 32
height = 16
cbb = CheckboxButton(10, 10)
cbb.debug_rect() # x: 10, y: 10, w: 16, h: 16
class BaseButton {
Rect rect;
public:
BaseButton(int x, int y, int w, int h) {
rect = Rect { x, y, w, h };
}
void debug_rect () {
printf("x: %d, y: %d, w: %d, h: %d\n", rect.x, rect.y, rect.w, rect.h);
}
};
class CheckboxButton: public BaseButton {
private:
using BaseButton::BaseButton;
protected:
public:
CheckboxButton(int x, int y): BaseButton { x, y, 16, 16 } {};
};
int main () {
CheckboxButton cbb { 10, 10 };
cbb.debug_rect();
}
我能想到的另一个解决方案是使用模板:
template<int W, int H>
class BaseButton {
Rect rect;
public:
BaseButton(int x, int y) {
rect = Rect { x, y, W, H };
}
void debug_rect () {
printf("x: %d, y: %d, w: %d, h: %d\n", rect.x, rect.y, rect.w, rect.h);
}
};
class CheckboxButton: public BaseButton<16, 16> {
public:
using BaseButton::BaseButton;
};
int main () {
CheckboxButton cbb { 10, 10 };
cbb.debug_rect();
}
模板
类基本按钮{
Rect-Rect;
公众:
基本按钮(整数x,整数y){
rect=rect{x,y,W,H};
}
void debug_rect(){
printf(“x:%d,y:%d,w:%d,h:%d\n”,rect.x,rect.y,rect.w,rect.h);
}
};
类CheckboxButton:公共基本按钮{
公众:
使用BaseButton::BaseButton;
};
int main(){
复选框按钮cbb{10,10};
cbb.debug_rect();
}
这两种解决方案都有效,但我的问题是它们的伸缩性不好。在我的简化示例中,我只是向基类构造函数添加了两个参数,而构造函数只是几行代码。如果配置参数为20,而构造函数比这复杂得多,该怎么办
什么是解决此类问题的标准C++方式?谢谢你解决了这个问题
在子对象中,您尝试在不使用显式构造函数的情况下初始化父对象的成员。在尝试这样做时,您可以在派生类中定义与父类中的成员同名的新成员变量,以便这些变量的名称被隐藏:
class CheckboxButton: public BaseButton {
protected:
const int width { 16 }; // new CheckboxButton::width,
// leaves BaseButton::width unchanged
const int height { 16 }; // leaves BaseButton::width unchanged
...
};
调试函数是在基类中定义的,它只知道BaseButton::width
和BaseButton::height
,这两个常量在0时保持不变
解决方案
一个好的做法是在构造函数中使用mem初始值设定项构造成员变量,因为这些变量用于构造成员:
class BaseButton {
protected:
const int width;
const int height;
Rect rect;
public:
BaseButton(int x, int y, int w, int h) : width{w}, height{h} {
rect = Rect { x, y, width, height };
}
BaseButton(int x, int y) : BaseButton(x,y,0,0) {} // delegate construction
// to other constructor
...
};
您可以看到,有一个包含两个参数的短构造函数,它将该构造转换为一个包含四个参数的构造函数,它还允许初始化height
和width
。顺便注意,构造函数体中的语句是在mem初始值设定项之后执行的
然后,派生类将调用相应的基构造函数:
class CheckboxButton: public BaseButton {
public:
CheckboxButton (int x, int y) : BaseButton(x,y, 16,16) {}
};
如果
width
和height
不是常量,则可以像在原始代码中一样,只为基类保留一个构造函数,并在派生构造函数的主体中分配新值。请查看此列表。你的问题太长,主题太广泛。请尽量缩小范围。为什么不让BaseButton
构造函数将宽度和高度作为参数呢?然后,您可以使用CheckboxButton
构造函数初始值设定项列表中的正确参数,创建自己的CheckboxButton
构造函数“调用”基本构造函数。如果您想获得一些灵感,可以访问。您甚至可以访问源代码(例如on),但我相信API参考对您来说更有趣。顺便说一句,在Qt之前,我使用了gtkmm,在:GTK+,在:OSF/Motif。。。不知何故,它们的工作原理都很相似。:-)因此,您的问题实际上不是关于构造过程中的虚拟调用(这是一个常见问题),而是关于如何处理GUI代码中的大量参数。这就是命名参数的习惯用法。这也是一个常见问题。@Someprogrammerdude这是我在问题中展示的第一个解决方案。正如我在问题的最后一部分中所说,当你没有两个参数(宽度和高度)而是10或20时,问题就会出现。