3

この現象を説明する助けが必要です。

#include <iostream>
using namespace std;

class A
{
public:
    void m() {cout<<"A::m "<<this<<endl;};
};

class B1:  public A
{
public:
    void m() {cout<<"B::m "<<this<<endl;};
};

class B2:  public A ,public B1
{
};

class D : public B2
{};

int main()
{
    B2 b;
    D d;
    A* a = &b; // Row 27
    //error: a = &d;  Base class 'A' is ambiguous // Row 28
    return 0;
}

Row27 のコードは機能するのに、Row28 のコードは機能しないのはなぜですか? 少し早いですがお礼を!

注:私は仮想継承をよく知っています.Row27とRow28の違いを知りたいだけです-一方がコンパイルエラーをスローするのに、もう一方がスローしないのはなぜですか?

4

2 に答える 2

1

非仮想継承を使用してから派生しているため、タイプのすべてのオブジェクトにAタイプの2つのサブオブジェクトが間接的に作成されます。コンパイラーは、ポインターから派生からポインターからベースへの変換を行うときに、参照するサブオブジェクトを明確にすることができず、エラーを発行します。AD

Aタイプのオブジェクトに対して生成されるタイプのサブオブジェクトを1つだけにするために、次から派生する継承パスに沿って仮想Dから継承を作成する必要があります。ADA

class B1:  virtual public A
{
    // ...
};

class B2:  virtual public A, public B1
{
};

編集:

Visual Studio 2010 SP1でサンプルをコンパイルしようとしましたが、次の定義について警告B2が表示されます。

class B2: public A, public B1
{
};

1>sotest.cpp(18): warning C4584: 'B2' : base-class 'A' is already a base-class of 'B1'
1>          sotest.cpp(6) : see declaration of 'A'
1>          sotest.cpp(11) : see declaration of 'B1'

言い換えれば、何らかの理由で、VC10はA冗長からの継承を考慮し、それを無視しているようです。これが、割り当てがA* a = &b;コンパイルされる理由です。class B2実際にはA、(からB1)を1回だけ継承します。DVC10にはおそらく無視する冗長な継承がなく、 2回(throughとthrough )Dから効果的に継承するため、同じことは当てはまりません。AB1B2

VC10がこのように動作する理由を無視し、この動作を抑制するコンパイラオプションがあるかどうかはわかりません。注目すべきことに、GCC4.7.2とClang3.2はどちらも、割り当てのコンパイルを拒否A* a = &b;します。

于 2013-01-21T17:44:03.643 に答える
1

将来のユーザーにとっては次のようです。

GCC 4.7.1 と Clang 3.2 で試してみましたが、仮想継承を使用しないとコンパイラ エラーが発生します。どのコンパイラを使用していますか? – アンディ・プロール

VS2010 は確かにコンパイルしますが、A からの B2 の継承を無視していることを示唆する警告を発行します。これが行 27 が機能する理由です。これは VS2010 の奇妙な動作だと思います。無効にする方法があるかどうかはわかりません (すべての警告をエラーと見なす以外に) – Andy Prowl

ありがとう@Andy Prowl。

于 2013-01-21T18:08:34.233 に答える