7
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;
}

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

4

3 に答える 3

5

標準セクション10.3p2の例では、宣言を使用しても仮想関数がオーバーライドされないことが明確になっています。

これは既知のg++バグです。

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

于 2011-01-12T14:05:45.837 に答える
1

using level1::foo;fooを参照する関数をlevel3クラスに導入しますlevel1::foo

メンバー宣言として使用されるusing宣言では、ネストされた名前指定子は、定義されているクラスの基本クラスに名前を付ける必要があります。このようなusing宣言は、メンバー名ルックアップによって検出された一連の宣言を導入します。

ただし、level1::fooは仮想であるため、これを呼び出すことによって、を呼び出す必要があると思いますlevel2::foo。したがって、iccは正しいはずです。

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

于 2011-01-12T14:01:16.080 に答える
0

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

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

「using」ディレクティブは、レベル3があり、その上でfooを呼び出すと、レベル1バージョンを呼び出す必要があることをコンパイラーに通知しているようですが、これはvテーブルに上書きされません。

gccは不整合のために間違って見えますが、標準が何を示しているのかわからないため、iccについてはよくわかりません。

于 2011-01-12T14:00:14.560 に答える