質問

struct level0
{
  virtual void foo() = 0;
};

struct level1 : level0
{
  virtual void foo() { cout <<" level1  " << endl; }
};

struct level2 : level1
{
  virtual void foo() { cout <<" level2 " << endl; }
};

struct level3 : level2
{
  using level1::foo;
};

int main()
{
  level1* l1 = new level3;
  l1->foo();
  level3 l3;
  l3.foo();
  return 0;
}

GCCを使用した上記のコードは与えます

level2
level1

しかし、ICCでは与えます

 level2
 level2

どちらが正しいのか、それとも標準によって未定義ですか?

編集:これは確かにバグがあることを証明しています、次の主な機能を考慮してください

int main()
{
    level3 l3;
    l3.foo();               // This prints level1

    level3* pl3 = &l3;
    pl3->foo();             // This prints level2

    level3& rl3 = l3;
    rl3.foo();              // This prints level1

    level3& rpl3 = *pl3;
    rpl3.foo();             // This prints level2

    return 0;
}

したがって、同じオブジェクトが直接異なる結果を生成し、同じタイプのポインターを介して使用すると、異なる結果が生成されます!!!

役に立ちましたか?

解決

標準セクション10.3p2の例では、宣言を使用することは明らかになります いいえ 仮想関数をオーバーライドします。

これは 既知のG ++バグ.

ご存知のように、動的タイプがわかっている場合ではなく、参照またはポインターを介してメンバー関数を呼び出すとき、バグは発生しません。

他のヒント

using level1::foo; 紹介します foo 機能します level3 を参照するクラス level1::foo.

メンバーの宣言として使用される使用法では、ネストされた名前の特定は、定義されているクラスの基本クラスに名前を付けます。このような使用法は、メンバー名ルックアップによって見つかった宣言のセットを紹介します。

しかし、それ以来 level1::foo 仮想です、私はそれを呼ぶことによってあなたは電話するべきだと思います level2::foo, 、したがって、ICCは正しいはずです。

とにかくよくわかりません。

もちろん、レベル1レベル1を取得する方法は次のとおりです。

struct level3 : level2
{
   virtual void foo() { level1::foo(); }
};

「使用」ディレクティブは、レベル3を持っていてFooを呼び出している場合、レベル1バージョンを呼び出す必要があることをコンパイラに通知しているようですが、これをV-Tableに上書きしていません。

GCCは矛盾のために間違っているように見えますが、標準が何を示しているかわからないため、ICCについてはわかりません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top