2

我有以下 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继承LabelsSurface属性?

4

3 回答 3

12

继承的成员不能出现在成员初始化列表中。试想一下,它们怎么会出现在派生类的成员初始化列表中,因为当它被执行时,它们(即基类成员)已经被创建(回想一下,基子对象是在派生类构造函数和成员之前创建的) -初始化列表)

如果它被允许,那么这将意味着基类成员将被允许多次初始化,这是没有意义的。在 C++ 中,对象不会多次初始化1 。初始化只发生一次;分配可以发生多次。

编写该代码的正确方法是参数化基类构造函数,并将xy作为参数传递给基类构造函数。

1. 我的意思是动态初始化只发生一次。但是,一个对象可以被初始化两次:一次在编译时称为静态初始化,另一次在运行时称为动态初始化。有关更多信息,请参阅:什么是 c++ 中对象的动态初始化?

于 2012-04-22T13:21:57.037 回答
1

您的构造函数可以重写为(只是一个伪代码来说明这一点,这不会编译):

Control(): Surface::x(10), Surface::y(10), name("control") { 
cout << "Control constructor" << endl; 
}

因此,您将初始化变量,这些变量已经(或可能)在您的父类中初始化。您不能两次初始化变量。x但是,您可以为and分配新值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; 
}
于 2012-04-22T13:22:39.907 回答
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;
};
于 2012-04-22T13:26:34.397 回答