匿名类的虚拟表

时间:2010-01-17 19:45:10

标签: c++ class virtual virtual-functions anonymous-class

我的代码中有类似的内容:

#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只是娇小,还是坚持标准?我错过了一些重要的东西吗?

3 个答案:

答案 0 :(得分:7)

看来这是VS 2008中的一个错误,可能是因为它覆盖或忽略了第一个未命名类的vtable,而第二个vtable则支持vtable,因为内部名称相同。 (当您明确命名一个时,vtable的内部名称不再相同。)

据我所知,从标准来看,这应该像你期望的那样工作,而gcc是正确的。

答案 1 :(得分:2)

可以看出MSVC如何从调试符号中弄错。它分别为匿名结构生成临时名称Child::<unnamed-type-First>Child::<unnamed-type-Second>。但是只有一个vtable,它被命名为Child::<unnamed-tag>::'vftable',两个构造函数都使用它。 vtable的不同名称肯定是bug的一部分。

在connection.microsoft.com上报告了几个与匿名类型相关的错误,这些错误都没有使其成为“必须修复”状态。不是你找到的那个,但是。也许解决方法太简单了。

答案 2 :(得分:1)

我可以确认这是VC编译器中的一个已知错误(它在VC10中存储);两个匿名类错误地共享vtable。

匿名结构是C ++标准的一部分。

编辑:匿名结构是一个含糊不清的术语。它可能意味着两件事:

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 ++。没有对象名称,您可以直接在外部类型的对象上访问字段“c”。这只是因为Visual Studio中的编译器扩展(在/ Za下会失败)

而编译 相比之下,匿名工会是合法的C ++。

我把这两者搞糊涂了,因为我们在这里称#1是一个“匿名结构”,我的大脑中的电线与#2交叉。