Mixing class and struct

2019-01-06 20:46发布

I'm well aware of the difference between class and struct, however I'm struggling to authoritatively say if this is well defined:

// declare foo (struct)
struct foo;

// define foo (class)
class foo {
};

// instance of foo, claiming to be a struct again! Well defined?
struct foo bar;

// mixing class and struct like this upsets at least one compiler (names are mangled differently)
const foo& test() {
   return bar;
}

int main() {
   test();
   return 0;
}

If this is undefined behaviour can someone point me in the direction of an authoritative (i.e. chapter and verse from ISO) reference?

The compiler with problems handling this (Carbide 2.7) is relatively old and all the other compilers I've tried it on are perfectly happy with this, but clearly that doesn't prove anything.

My intuition was this ought to be undefined behaviour but I can't find anything to confirm this and I'm surprised that none of the GCC versions or Comeau so much as warned about it.

6条回答
一纸荒年 Trace。
2楼-- · 2019-01-06 21:09

It looks to me like it's defined behavior. In particular, §9.1/2 says:

A declaration consisting solely of class-key identifier ; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name into the current scope.

The standard distinguishes between using class, struct or union when defining a class, but here, talking about a declaration, no such distinction is made -- using one class-key is equivalent to any other.

查看更多
贼婆χ
3楼-- · 2019-01-06 21:10

In C++, a struct is a class. Specifically:

A structure is a class defined with the class-key struct. (ISO/IEC FDIS 14882:1998(E) 9-4)

This implies that your class, which was not defined with struct, is definitely not a struct. Therefore, your forward declaration with the struct class-key is erroneous. I'm not aware of any part of the specification that allows a forward declaration to use a class-key that is clearly wrong. I'm sure that the lenient compilers in question treat structs and classes equally and are glossing over the incorrect declaration. An error may not be required from the compiler in this scenario, but neither should it be unexpected.

查看更多
迷人小祖宗
4楼-- · 2019-01-06 21:13

MSVC10 throws a warning, and the warning page states that the type given in the definition will be used.

http://msdn.microsoft.com/en-us/library/695x5bes.aspx

查看更多
家丑人穷心不美
5楼-- · 2019-01-06 21:29

I have no idea whether or not this is undefined (or any of the other categories of not-strictly-conforming) per the C standard, but I do know that if you have two translation units that don't agree on whether a type 'foo' is declared as a 'class' or a 'struct', like so:

TU 1

struct foo;
void f(foo&) { ... }

TU 2

class foo { ... };
void f(foo&);

void g()
{
  foo x;
  f(x);
}

then, at least some compilers (notably MSVC++) will mangle the name of f differently in each translation unit, so the definition of f in TU 1 does not satisfy the reference to f in TU 2 and you get a link error. This comes up in real life when you have a header A.h that defines class A and needs to refer to classes B, C, and D but a forward declaration of them suffices (so it, quite sensibly, does not include B.h etc) -- you better use the same keyword for those forward declarations that the actual definitions do!

查看更多
爷的心禁止访问
6楼-- · 2019-01-06 21:32

Technically the code is ok, according to the language standard. However, as at least one of the most popular compilers issues a warning for this, it doesn't work in practice.

"In theory, there is no difference between theory and practice. In pratice, there is."

查看更多
该账号已被封号
7楼-- · 2019-01-06 21:35

From Warning C4099: type name first seen using 'class' now seen using 'struct' (MS VS 2k8) it appears that at least some compilers mangle differently depending on keyword used, so best not to rely on it even if it's technically allowed (of which I can't find a confirming reference).

查看更多
登录 后发表回答