【问题标题】:Mixing class and struct混合类和结构
【发布时间】:2011-06-19 11:32:55
【问题描述】:

我很清楚difference between class and struct,但是我很难权威地说这是否定义明确:

// 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;
}

如果这是未定义的行为,有人可以指出权威(即 ISO 中的章节和诗句)参考的方向吗?

处理此问题的编译器 (Carbide 2.7) 相对较旧,我尝试过的所有其他编译器都对此非常满意,但显然这并不能证明什么。

我的直觉是这应该是未定义的行为,但我找不到任何东西来证实这一点,我很惊讶 GCC 版本或 Comeau 都没有警告过它。

【问题讨论】:

  • AFAIK,结构是一个具有公共成员的类;也许编译器会将结构前向声明“变形”为前向类声明。 (??)
  • @Max: 这样做是必须的还是只是为了好看?
  • @Matthieuh - 我不认为这是重复的,因为我问的是它是否是明确定义的行为,而不是一个(可能不符合标准的)编译器产生的警告意味着什么。跨度>
  • @peoro:我无法让 Clang 的在线演示发出警告,你有文字吗?

标签: c++ class struct undefined-behavior


【解决方案1】:

我不知道这是否根据 C 标准未定义(或任何其他不严格符合的类别),但我知道如果您有两个翻译单元不同意是否类型“foo”被声明为“类”或“结构”,如下所示:

TU 1

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

TU 2

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

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

那么,至少有一些编译器(尤其是 MSVC++)会在每个翻译单元中以不同的方式处理 f 的名称,因此 TU 1 中 f 的定义不满足 TU 2 中对 f 的引用和你得到一个链接错误。当你有一个定义类A的标题A.h并需要引用类BCD时,这会在现实生活中出现,但它们的前向声明就足够了(所以它,相当明智地,是否包含B.h等)-您最好对那些实际定义所做的前向声明使用相同的关键字!

【讨论】:

  • 新的 MSVC 版本会这样做还是 VC6 主义?
  • 我确实看到过它的版本比 VC6 更新,但我不确定如何最近。
  • 在 Visual Studio 2015 中仍然会发生这种情况
【解决方案2】:

在 C++ 中,结构是一个类。具体来说:

结构是一个定义的类 类键struct。 (ISO/IEC FDIS 14882:1998(E) 9-4)

这意味着您的类(未使用struct定义)绝对不是结构。因此,您使用 struct class-key 的前向声明是错误的。我不知道规范中允许前向声明使用明显错误的类键的任何部分。我确信有问题的宽松编译器平等地对待结构和类,并且掩盖了不正确的声明。在这种情况下,编译器可能不需要错误,但也不应该是意外的。

【讨论】:

  • 认为这是正确的。类名只是foo,它不包括struct 类键。但是,标准中没有提到可以。
  • @John Dibling:您可能想阅读this,了解foo x;struct foo x; 之间的区别(基本上,structclass 关键字不是名称的一部分,而是命令编译器查看特定标识符空间,即用户定义类型的空间)
  • 大错特错。 @DavidRodríguez-dribeas,您的链接指向一个明确关于 C 的问题,而 C++ 的工作方式不同。请参见 ISO/IEC 9899/1990 第 1.7.5.3 节。
  • @DavidRodríguez-dribeas:参见第 7.1.5.3 节第 3 段 - “详细类型说明符class-keyenum 关键字/i> 应与 elaborated-type-specifier 中的名称所指的声明以实物方式一致。 ... 因此,在任何 elaborated-type-specifier 中, enum 关键字应用于引用枚举(7.2),union class-key 应用于引用联合(第 9 条)和 两者 应使用classstruct class-key指代使用classstruct 声明的类(第9 条)类键。” [大胆的我]
  • (cont'd) 用structclass 声明的任何东西都是一个类;规范在它们之间的唯一区别在于,在一个标识符和继承中默认为公共的,而在另一个中,它们默认为私有的。尽管编译器没有定义标准,但请注意 G++ 4.6 允许您定义 class A { public: ... }; 并将其实例化为 struct A a;。我知道 MSVC 对名称的处理方式不同,但是,微软不遵守 ISO 标准吗?谁会想到?
【解决方案3】:

MSVC10 抛出一个警告,警告页面声明将使用定义中给出的类型。

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

【讨论】:

  • 这不能回答问题。问题是,行为是 UB 吗?
  • “社区内容”中的示例看起来像是取自标准文档,但我在我拥有的各种文档中都找不到它...
【解决方案4】:

在我看来,它就像是已定义的行为。特别是,§9.1/2 说:

仅由 class-key identifier ; 组成的声明要么是对 当前范围内的名称或标识符的前向声明作为类名。它将类名引入当前作用域。

标准在定义一个类时区分使用classstructunion,但是在这里,谈到声明,没有这样的区别——使用@987654326 @ 等价于任何其他。

【讨论】:

  • 这听起来有点冒昧。 “类键标识符”对我来说意味着类键必须是类键,就像标识符必须是类标识符一样,而不仅仅是任意标识符。它没有说明,也没有暗示(对我来说)所有类键都是等价的。
  • @Eric Mickelsen:我不能同意。它特别说“名称”,清楚地表明所指的名称。 class-key,OTOH,具体定义为表示 classstructunion 中的任何一个,这里没有任何内容将其限制为三者之一。
  • @eric §7.1.6.3/3 (Elaborated type specifiers, latest C++0x doc I've seen)说“类或结构类键应用于引用一个类(第 9 条)使用类或结构类键声明。”我认为可以以任何一种方式阅读。无论哪种方式,都只需要一个词来阐明这句话的含义……
  • @awoodland +1,这与我在标准中找到的引用相同。如果您阅读了同一段中的前几句,我的解释是structclass 中的任何一个都可以使用,而不管声明中使用了structclass@987654335 @ 关键字应用于引用枚举,union 关键字应用于引用联合,在完整段落的上下文中可以看到 classstruct...,我倾向于认为它们是可以互换的。
  • FWIW,Herb Sutter(ISO 委员会成员)明确表示这是有效的 - 请参阅此处的第 154 页勘误表gotw.ca/publications/xc++-errata.htm - 事实上,在 Exceptional C++ 的早期打印运行中依赖它。前向声明可以使用任何类、结构、联合,并且类型语义是从完整的类型定义派生的。微软这样做的事实并不能真正说明标准所说的内容。
【解决方案5】:

Warning C4099: type name first seen using 'class' now seen using 'struct' (MS VS 2k8) 看来,至少有一些编译器会根据所使用的关键字进行不同的处理,因此即使技术上允许(我找不到确认参考),最好不要依赖它。

【讨论】:

    【解决方案6】:

    根据语言标准,从技术上讲,代码是可以的。但是,由于至少有一个最流行的编译器会为此发出警告,因此它在实践中不起作用。

    “理论上,理论和实践没有区别。实践中,有区别。”

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-21
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多