4

複数レベルの継承を示す次のサンプル コードを検討してください。

Case1 : ここでは、クラスderived1base仮想継承によってクラスから派生し、クラスはクラスから直接derived2派生します。derived1

class base
{

};

class derived1 : virtual public base
{

};

class derived2 : public derived1
{

};

Case2 : 仮想継承が関係しないことを除いて、Case1 と同じです。

class base
{

};

class derived1 : public base // no virtual inheritance
{

};

class derived2 : public derived1
{

};

derived2どちらの場合も、クラスのオブジェクトを作成するとします。

  1. のオブジェクトに含まれるサブオブジェクトに関して、Case1 と Case2 はどのように異なりますderived2か?

  2. Case1 は Case2 よりも重要ですか?

PS: 多重継承中の仮想基本クラスの重要性は明らかです。

4

4 に答える 4

3

継承階層に基本クラスの複数のインスタンスがない場合、基本クラスに関して (少なくとも) 考慮すべき他の 2 つの問題がありvirtualます。

まず、仮想基底クラスは常に、構築中の最も派生したクラスによって、非仮想基底クラスの前に初期化されます。これは、中間クラスがメンバー初期化リストで仮想基底クラス コンストラクターにパラメーターを渡す場合に最も明白です。これらの初期化子は無視されます。また、基本クラスの構築順序にも違いが生じる可能性があります。

static_cast第 2 に、仮想基底クラスからそれを継承するクラスへの変換を実行することはできません。

于 2012-07-11T05:54:53.280 に答える
2

仮想継承を使用すると、追加情報が保存されます。これは、ダイアモンドの状況の場合に動的キャストが派生クラスに適切に解決できるようにするためです。コードにはひし形の状況がないため、情報は使用されません。

基本クラスにデータ メンバーを追加すると、追加情報を表示できます。

class base {
protected:
    int i;
};

2 つのケースのそれぞれの派生クラスのサイズを出力すると、ケースによってサイズが異なることがわかります。

編集: Charles Bailey は、仮想継承を使用した場合のセマンティックの違いについて優れた点を指摘しています。彼の最初の点は特に興味深いものであり、もっと検討する必要があります。彼のポイントは、基本的derived2に、暗黙のダイアモンド トポロジーを持っているということです。つまり、derived1仮想的に継承すると仮定すると、次のようになりbaseます。

class base {};
class derived1 : virtual public base {};

次に、これら 3 つのバージョンの に違いはなくderived2、すべて最初のバージョンと同じように動作します。

class derived2 : virtual public base, public derived1 {};
class derived2 : public derived1, virtual public base {};
class derived2 : public derived1 {}

derived1これは、次のようなクラス(つまり、仮想継承を使用したクラス) から派生したときに作成される暗黙のひし形があることを意味します。

    base
     |  \
     |   \.(virtual)
     |   / \
     |  /___\
     |    |
     | derived1
     |   /
     |  /
     |./
     / \ 
    /___\
      |
   derived2 

ポイントをさらに説明するために、これはderived1仮想継承を使用する場合に許可されます。

class derived2 : public derived1 {
public:
    derived2 () : base() {}
};

ただし、derived1仮想継承を使用しない場合は許可されません。

于 2012-07-11T05:15:25.123 に答える
1

仮想継承は、クラスが基本クラスとして複数回含まれている場合にのみ重要になります。実際、指定子virtualはここで「一度だけ含める」ことを意味します。

多重継承がない場合、同じクラスを複数回指定することはできません (循環継承は明らかな構文エラーです)。次に、コンパイラの最適化がどれほどスマートかということになります。コンパイラが完璧であれば、違いはありません。実際には、コンパイラが多重継承に関連するものをクラスに追加するというリスクを負うことになります。言語の一部の機能が使用される頻度が低いほど、コンパイラが混乱するリスクが大きくなります。Compiler は通常、高品質のプログラムですが、それでもこれは単なるプログラムです。

于 2012-07-11T05:09:39.613 に答える
1

あなたの場合、仮想継承は重要ではありません。
次のようなダイアモン継承のためにのみインデントされます。

B: A
C: A
D: B, C

この場合、どちらの場合も A からの継承は仮想でなければなりません。

于 2012-07-11T04:59:19.200 に答える