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'

s プロパティControlLabel継承しない理由がわかりません。Surface

4

3 に答える 3

12

継承されたメンバーは、メンバー初期化リストに表示できません。派生クラスの member-initialization-list にどのように表示されるかを考えてみてください。実行されるまでに、それら (つまり、基本クラスのメンバー) が既に作成されているためです(派生クラスのコンストラクターとメンバーの前に基本サブオブジェクトが作成されることを思い出してください)。 -initialization-list) .

許可されている場合、それは基本クラスのメンバーを複数回初期化できることを意味し、意味がありません。C++ では、オブジェクトが複数回初期されることはありません。初期化は一度だけ行われます。割り当ては何度も発生する可能性があります。

そのコードを記述する適切な方法は、基本クラス コンストラクターをパラメーター化し、 と の値を引数として基本クラス コンストラクターに渡すことxですy

1. つまり、動的初期化は 1 回だけ行われます。ただし、オブジェクトは 2 回初期化できます。1 回はコンパイル時に静的初期化と呼ばれ、次に実行時に動的初期化と呼ばれます。詳細については、これを参照してください: What is dynamic initialization of object in c++?

于 2012-04-22T13:21:57.037 に答える
1

コンストラクターは次のように書き直すことができます (ポイントを説明するための単なる擬似コードであり、これはコンパイルされません)。

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

したがって、親クラスで既に初期化されている (または既に初期化されている可能性がある) 変数を初期化します。変数を 2 回初期化することはできません。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; 
}
于 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 に答える