views:

181

answers:

3

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 behavior, if any, is correct? Is VS just being prissy, or is it adhering to the standard? Am I missing something vital here?

+6  A: 

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.

Roger Pate
(+1) well written explanation.
Hassan Syed
+2  A: 

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.

Hans Passant
+1  A: 

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.

Terry Mahaffey
Unnamed classes are standard C++ and are sometimes called "anonymous" instead of "unnamed".
Roger Pate
@Roger, What I said is correct. I said anonymous **structs** ; not anonymous **classes**. Anonymous classes are part of the C++ standard. Anonymous structs are a C thing, and not part of C++ (although they are widely supported vendor extension, including VC).
Terry Mahaffey
"A structure is a class defined with the class-key struct ..." [9/4] **Structs are classes.**
Roger Pate
See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1289.htm. This is the C++ Standards Committee statement on the topic. Note the part which says "ANSI C++ anonymous structs: NO". Google the topic and you'll see a lot of discussion around it, and the consensus is they are not part of the standard.
Terry Mahaffey
And from MSDN: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx, "A Microsoft C extension...C++ does not allow anonymous structures."
Terry Mahaffey
The msdn link is talking about something completely different and unrelated from what is used in this question, which may be the source of your confusion. And rereading n1289, I can see it's talking about something other than unnamed classes too. In the OP's code, it is the class names which are absent, not the object names.
Roger Pate
@Roger, you're right - I am confused. I keep talking about anonymous structs (and give links talking about them), but here it's an unnamed struct, not an anonymous struct! Thanks
Terry Mahaffey
Maybe you should edit the answer?
Potatoswatter
@Potatoswatter, @Roger, I updated the answer to try to give this comment thread some context
Terry Mahaffey