11

仮想継承を使用して菱形継承問題を解決できることはわかっています。

例えば:

   class Animal // base class
   {
     int weight;
     public:
     int getWeight() { return weight;};
   };
   class Tiger : public Animal { /* ... */ }; 
   class Lion : public Animal { /* ... */ };
   class Liger : public Tiger, public Lion { /* ... */ }; 
   int main()
   {
     Liger lg ;
     /*COMPILE ERROR, the code below will not get past
     any C++ compiler */
     int weight = lg.getWeight();
   }

このコードをコンパイルすると、あいまいなエラーが発生します。ここで私の質問は、コンパイラがこのあいまいさの問題(菱形継承問題)を内部でどのように検出するかです。

4

3 に答える 3

4

コンパイラーは、すべてのクラスのすべてのメンバーをリストするテーブルを作成します。また、任意のクラスの継承チェーンを上下に移動できるリンクもあります。

メンバー変数(この例では重み)を見つける必要がある場合、コンパイラーは実際のクラス(この場合はLiger)から開始します。そこにウェイトメンバーが見つからないため、親クラスに1レベル上に移動します。この場合は2つあるため、TigerとLionの両方をスキャンして名前の重みのメンバーを探します。まだヒットがないので、もう1レベル上げる必要がありますが、このレベルのクラスごとに1回ずつ、2回行う必要があります。これは、必要なメンバーが継承ツリーのあるレベルで見つかるまで続きます。あるレベルで、すべての多重継承ブランチを考慮して1つのメンバーだけが見つかった場合、必要な名前のメンバーが2つ以上見つかった場合、どちらを選択するかを決定できないため、エラーが発生します。

于 2011-09-12T06:21:06.440 に答える
3

コンパイラがクラスの関数ポインタのテーブルを作成するとき、すべてのシンボルがそのクラスに1回だけ出現する必要があります。この例では、 inとinのgetWeight2回表示されます(実装されていないため、ツリーを上って検索します)。したがって、コンパイラはスタックします。TigerLionLiger

実際、それはかなり簡単です。

于 2011-09-12T06:05:24.190 に答える
1

コードを使用すると、ライガーの構造は次のようになります。

Liger[Tiger[Animal]Lion[Animal]]

Animalポインターから関数を呼び出す場合Liger、実際にはライガーが変換できる2つの動物があります(したがって、あいまいさ)

仮想継承は次のような構造を生成します

Liger[Tiger[*]Lion[Animal]]
            \-----/

現在、両方の拠点から間接的に到達可能な動物は1つしかないため、ライガーから動物への変換はもうあいまいです。

于 2011-09-12T07:10:20.843 に答える