12


0

匿名クラスの仮想テーブル

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

#include
#include

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

興味深いのは、ベースから派生した構造体の名前( struct s1:public Base)を指定すると、正しく機能することです。

正しい場合、どの動作が正しいですか? VSはただのうるさいですか、それとも標準に準拠していますか? ここで何か重要なものを見逃していますか?

3 Answer


7


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

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


2


MSVCがデバッグシンボルからどのように間違っているかがわかります。 匿名構造体の一時的な名前、それぞれ `Child ::`と `Child ::`を生成します。 ただし、vChildは1つしかなく、 `Child

'vftable'`という名前で、両方のコンストラクタが使用します。 vtableの別の名前は確かにバグの一部です。

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


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では失敗します)

3対照的に、匿名結合は正当なC ++です。

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