我有以下C ++代码:
#include <iostream>
#include <string>
using namespace std;
class Surface
{
public:
virtual void draw();
protected:
int x,y;
};
class Control: public Surface
{
public:
Control(): x(10), y(10), name("control") { cout << "Control constructor" << endl; }
void draw() {}
protected:
string name;
};
class Label: public Control
{
public:
Label(): x(10), y(10), name("label"), text("label") { cout << "Label constructor" << endl; }
void draw() { cout << "drawing a label" << endl; }
protected:
string text;
};
int main(int argc, const char *argv[])
{
Label l;
return 0;
}
尝试编译时,我收到以下错误:
$ g++ main.cpp
main.cpp: In constructor 'Control::Control()':
main.cpp:16:16: error: class 'Control' does not have any field named 'x'
main.cpp:16:23: error: class 'Control' does not have any field named 'y'
main.cpp: In constructor 'Label::Label()':
main.cpp:25:14: error: class 'Label' does not have any field named 'x'
main.cpp:25:21: error: class 'Label' does not have any field named 'y'
main.cpp:25:28: error: class 'Label' does not have any field named 'name'
我不明白为什么Control
和Label
没有继承Surface
属性?
答案 0 :(得分:12)
继承的成员不能出现在member-initialization-list中。试想一下,它们如何出现在派生类的成员初始化列表中,因为当它被执行时,它们(即基类成员)已经被创建(回想一下基础子对象在派生类之前创建)构造函数和成员初始化列表)。
如果允许,那么这意味着基类成员将被允许多次初始化,这没有意义。在C ++中,对象不会多次初始化 1 。初始化只发生一次;任务可以多次发生。
编写该代码的正确方法是参数化基类构造函数,并将x
和y
的值作为参数传递给基类构造函数。
1。我的意思是动态初始化只发生一次。但是,对象可以初始化两次:一次在编译时称为 static 初始化,然后在运行时称为动态初始化。有关更多信息,请参阅:What is dynamic initialization of object in c++?
答案 1 :(得分:1)
您的构造函数可以重写为(只是一个伪代码来说明这一点,这不会编译):
Control(): Surface::x(10), Surface::y(10), name("control") {
cout << "Control constructor" << endl;
}
因此,您将初始化变量,这些变量已经(或可能)已在您的父类中初始化。您不能两次初始化变量。
但是,您可以为x
和y
:
Control(): name("control") {
cout << "Control constructor" << endl;
/*Surface::*/x = 10;
/*Surface::*/y = 10;
}
或者您可以创建构造函数Surface(int x, int y)
并将x和y传递到那里:
Control(): Surface(/*x=*/10, /*y=*/10), name("control") {
cout << "Control constructor" << endl;
}
答案 2 :(得分:1)
如果您为基类定义了适当的参数化构造函数来处理初始化它们自己的字段,那么您的问题将不复存在。将它留给子类是糟糕的设计。因此,您的代码可以重写为:
class Surface
{
public:
Surface(int x_, int y_): x(x_), y(y_) { cout << "Surface constructor" << endl; }
virtual void draw();
protected:
int x,y;
};
class Control: public Surface
{
public:
Control(int x_ = 10, int y_ = 10, string name_ = "control")
: Surface(10, 10), name(name_) { cout << "Control constructor" << endl; }
void draw() {}
protected:
string name;
};
class Label: public Control
{
public:
Label(): Control(10, 10, "label"), text("label") { cout << "Label constructor" << endl; }
void draw() { cout << "drawing a label" << endl; }
protected:
string text;
};