12

私のコードにはこれに似たものがあります:

#include <iostream>
#include <cstdlib>

struct Base
{
  virtual int Virtual() = 0;
};

struct Child
{
  struct : public Base
  {
    virtual int Virtual() { return 1; }
  } First;

  struct : public Base
  {
    virtual int Virtual() { return 2; }
  } Second;
};

int main()
{
  Child child;
  printf("ble: %i\n", ((Base*)&child.First)->Virtual());
  printf("ble: %i\n", ((Base*)&child.Second)->Virtual());

  system("PAUSE");
  return 0;
}

これにより、次の出力が得られると予想されます。

ble: 1
ble: 2

GCC(3.4.5だと思います)でコンパイルすると、そうなります。

ただし、これを Visual Studio 2008 でコンパイルして実行すると、次のようになります。

ble: 2
ble: 2

興味深いのは、Base から派生した構造体に名前 ( struct s1 : public Base) を付けると、正しく動作することです。

あるとすれば、どの動作が正しいですか? VS は単純なだけですか、それとも標準に準拠していますか? ここで重要な何かが欠けていますか?

4

3 に答える 3

7

これは VS 2008 のバグのようです。おそらく、内部名が同一であるため、最初の名前のないクラスの vtable を上書きまたは無視して、2 番目の vtable を優先するためです。(明示的に名前を付けると、vtable の内部名は同一ではなくなります。)

標準からわかる限り、これは期待どおりに機能し、gcc は正しいです。

于 2010-01-17T20:12:45.917 に答える
2

デバッグ シンボルから、MSVC がどのように間違っているかがわかります。匿名構造体の一時的な名前をそれぞれ生成しますChild::<unnamed-type-First>およびChild::<unnamed-type-Second>. ただし、vtable は 1 つしかなく、名前が付けられChild::<unnamed-tag>::'vftable'ており、両方のコンストラクターがそれを使用します。vtable の別の名前は確かにバグの一部です。

匿名型に関連するいくつかのバグが connection.microsoft.com で報告されていますが、いずれも「修正が必要」な状態にはなりませんでした。しかし、あなたが見つけたものではありません。回避策が単純すぎるのかもしれません。

于 2010-01-17T23:00:58.510 に答える
1

これが VC コンパイラの既知のバグであることを確認できます (VC10 に格納されています)。2 つの匿名クラスが誤って vtable を共有しています。

匿名構造体は、C++ 標準の一部ではありません。

編集:匿名構造体は、あいまいな用語のようなものです。次の 2 つのことを意味します。

class outer
{
public:
    struct {
        int a;
        int b;
    } m_a; // 1

    struct {
        int c;
    };     // 2

    union {
        int d;
        int e;
    };     // 3
};

1 はここで起こっていることです。匿名構造体よりも適切な名前は「名前のない構造体」です。構造体型自体には名前がありませんが、オブジェクトには名前があります (m_a)。

2 は無名構造体とも呼ばれ、正当な C++ ではありません。オブジェクト名はなく、outer 型のオブジェクトのフィールド 'c' に直接アクセスできるという考え方です。これは、Visual Studio のコンパイラ拡張機能によってのみコンパイルされます (/Za では失敗します)。

対照的に、無名共用体は正当な C++ です。

ここでは #1 を「匿名構造体」と呼んでおり、脳内の配線が #2 と交差しているため、この 2 つを混同しました。

于 2010-01-18T00:29:45.623 に答える