Virtual tables on anonymous classes
I have something similar to this in my code:
#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;
}
I'd expect this to give this output:
ble: 1
ble: 2
and it does so, when compiled under GCC (3.4.5 I believe).
Compiling and running this under Visual Studio 2008 however, gives this:
ble: 2
ble: 2
What is interesting, is that if I give the Base-derived structs names (struct s1 : public Base
), it works correctly.
Which b开发者_Go百科ehavior, if any, is correct? Is VS just being prissy, or is it adhering to the standard? Am I missing something vital here?
It appears this is a bug in VS 2008, possibly because it overwrites or ignores the vtable for the first unnamed class in favor of the vtable for the second since the internal names are identical. (When you name one explicitly, the internal names for the vtables are no longer identical.)
As far as I can tell from the standard, this should work as you expect and gcc is right.
It is visible how MSVC is getting it wrong from the debugging symbols. It generates temporary names for the anonymous structs, respectively Child::<unnamed-type-First>
and Child::<unnamed-type-Second>
. There is however only one vtable, it is named Child::<unnamed-tag>::'vftable'
and both constructors use it. The different name for the vtable surely is part of the bug.
There are several bugs reported at connection.microsoft.com that are related to anonymous types, none of which ever made it to "must-fix" status. Not the one you found though, afaict. Maybe the workaround is just too simple.
I can confirm this is a known bug in the VC compiler (and it repos in VC10); the two anonymous classes are incorrectly sharing a vtable.
Anonymous structs are not part of the C++ standard.
Edit: Anonymous structs are kind of an ambiguous term. It can mean two things:
class outer
{
public:
struct {
int a;
int b;
} m_a; // 1
struct {
int c;
}; // 2
union {
int d;
int e;
}; // 3
};
1 is what is going on here, a better name than anonymous struct would be "unnamed struct". The struct type itself doesn't have a name, but the object does (m_a).
2 is also known as an anonymous struct, and isn't legal C++. There is no object name, and the idea is you could access the field 'c' directly on objects of type outer. This compiles only because of a compiler extension in Visual Studio (will fail under /Za)
3 Anonymous unions, by contrast, are legal C++.
I confused the two, because here we're calling #1 an "anonymous struct", and wires in my brain crossed with #2.
精彩评论