12

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?

GhassanPL
  • 2,679
  • 5
  • 32
  • 40
  • 1
    Works as expect in gcc. Though to be blunt I was it expecting it not to compile. – Martin York Jan 17 '10 at 20:01
  • 2
    *VS adhering to the standard*? Ha ha ha ha ha... – wallyk Jan 17 '10 at 20:04
  • 3
    Hey, VC++ has gotten much better at that. – GManNickG Jan 17 '10 at 20:05
  • VS is pretty good at sticking to the standard. Off-hand I can only think of a couple of features it doesn't support. Two-phase name lookup, exception specifications and the `export` keyword. And the two last ones are generally considered Bad Ideas anyway. (Last I checked, the plan for C++0x was to deprecate exception specifications, and most compilers pretend that `export` never existed) – jalf Jan 17 '10 at 20:13
  • In most cases where VC breaks from the standard today its for historic reasons and would break large existing code-bases if they changed the defaults... notably the extensions that were neccessary for COM. – Georg Fritzsche Jan 17 '10 at 20:14
  • @gf interesting, I would be interested in any technical documentation outlining these, got any references ? – Hassan Syed Jan 18 '10 at 00:36
  • VC6 was a joke for conformance (a reputation that seems to have carried forward to today in some minds) - but be fair, it was released in 1998, the same year the standard was ratified. VC10 (and VC9, for that matter) is one of most conformant compilers on the market. And @gf, what extensions are you referring to? – Terry Mahaffey Jan 18 '10 at 00:37
  • Still broken in VS2013, many years later... – Joe Sep 17 '15 at 07:41
  • It is, however, fixed in Visual Studio 2015. – GhassanPL Sep 17 '15 at 10:05

3 Answers3

7

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.

2

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
  • 922,412
  • 146
  • 1,693
  • 2,536
1

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
  • 11,775
  • 1
  • 35
  • 44
  • Unnamed classes are standard C++ and are sometimes called "anonymous" instead of "unnamed". –  Jan 18 '10 at 00:46
  • @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 Jan 18 '10 at 00:51
  • "A structure is a class defined with the class-key struct ..." [9/4] **Structs are classes.** –  Jan 18 '10 at 00:53
  • 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 Jan 18 '10 at 00:58
  • And from MSDN: http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx, "A Microsoft C extension...C++ does not allow anonymous structures." – Terry Mahaffey Jan 18 '10 at 01:05
  • 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. –  Jan 18 '10 at 01:16
  • @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 Jan 18 '10 at 01:22
  • @Potatoswatter, @Roger, I updated the answer to try to give this comment thread some context – Terry Mahaffey Jan 18 '10 at 06:12