7

型階層内のコンストラクターのルールを呼び出すのに苦労しています。これが私がすることです:

class A{
protected:
    int _i;
public:
    A(){i = 0;}
    A(int i) : _i(i){}
    virtual ~A(){}
    virtual void print(){std::cout<<i<<std::endl;}
};

class B : virtual public A{
protected:
    int _j;
public:
    B() : A(){_j = 0;}
    B(int i, int j) : A(i), _j(j){}
    virtual ~B(){}
    virtual void print(){std::cout<<i<<", "<<j<<std::endl;}
};

class C : virtual public B{
protected:
    int _k;
public:
    C() : B(){_k = 0;}
    C(int i, int j, int k} : B(i,j), _k(k){}
    virtual ~C(){}
    virtual void print(){std::cout<<i<<", "<<j<<", "<<k<<std::endl;}
};

int main(){
    C* myC = new C(1,2,3);
    myC->print();
    delete myC;
    return 0;
}

ここで、新しいC(1,2,3)がB(1,2)のコンストラクターを呼び出し、次にコンストラクターA(1)を呼び出して_i = 1、_j = 2、_k=を格納するようにします。 3.3。クラスCのインスタンスmyCを作成するとき、何らかの理由で私にはわかりませんが、最初に呼び出されるコンストラクターはAの標準コンストラクター、つまりA :: A()です。保護された変数_iに値0が割り当てられるため、これは明らかに間違った結果につながります。コンストラクターA(1)が呼び出されることはありません。なんでそうなの?これは非常に直感的ではありません。目的の動作を実現するために、型階層内のすべてのコンストラクターを明示的に呼び出さないようにする方法はありますか?

助けてくれてありがとう!

4

4 に答える 4

7

virtualここで本当に継承が必要ですか?非常に最初の仮想ベース ctor が最初に呼び出されるため、問題が発生しますが、継承するときに何も指定しませんC(B後者は既にA仮想的に継承されているため、default が呼び出されました)。

1つの解決策は、仮想継承を削除することです... Arne Mertzの回答で述べたように。もう1つ(本当に仮想継承が必要な場合)は、ctorAから明示的に呼び出すことですC

C(int i, int j, int k} : A(i), B(i,j), _k(k){}
于 2013-01-22T10:41:06.793 に答える
6

これは、仮想継承を使用したためです。これは、複数の継承が存在する場合にのみ意味があります。通常どおり継承するだけで、すべてが期待どおりになります。

于 2013-01-22T10:36:35.253 に答える
6

仮想継承を使用する場合、最も派生したクラスは、そのすべての仮想ベースのコンストラクターを直接呼び出す必要があります。この場合、 のコンストラクターはおよびCのコンストラクターを呼び出す必要があります。コンストラクターを呼び出すだけなので、デフォルトのコンストラクターが使用されます。コンストラクターが別のコンストラクターを呼び出しても問題ありません。これは仮想基底クラスであるため、この呼び出しは無視されます。BABABA

この問題を回避するには 2 つの方法があります。明示的にA(int)コンストラクターを呼び出します。

C(int i, int j, int k} : A (i), B(i,j), _k(k){}

または、仮想の代わりに通常の継承を使用します。

于 2013-01-22T10:42:08.330 に答える
0

なぜ仮想継承を宣言するのですか? クラス B: virtual public A { ... から virtual キーワードを削除すると、コードは正常に動作します。virtual A を宣言することにより、C は A() を直接呼び出します。virtual を削除すると、C は A() を呼び出しません。

于 2016-09-23T15:14:30.937 に答える