【问题标题】:In C++, why struct is in fact class?在 C++ 中,为什么结构实际上是类?
【发布时间】:2010-12-13 10:12:56
【问题描述】:

other topic 和那里的回复让我问了这个问题:

为什么 C++ 允许 struct 表现得像 class?一方面,C++ 通过使其成员默认为 public 使其与 C-struct 兼容(就像在 C 中一样),而另一方面,它通过允许它使其看起来像类从类继承,并应用其他面向对象的技术(不再像C-struct)。为什么它不让它只是简单的旧 C-struct 没有 OOP?有什么特殊原因吗?

【问题讨论】:

  • 您最近关于“为什么是 C++ 等等等等”的问题都可以用“为什么不?”来回答。我喜欢 C++ 这样做,开发标准的人也喜欢它,这就是他们这样做的原因。
  • @ybungalobill :现在我不仅在探索 C++ 语法/用法,还在探索它们背后的哲学。这就是为什么你会看到“Why C++ blah blah..”。 :-)
  • 那么或许你应该阅读《c++的设计与演进》
  • @jk :似乎。我想我应该开始阅读了。感谢您的建议。:-)

标签: c++ oop class struct backwards-compatibility


【解决方案1】:

它允许以更自然的方式将现有结构与 C++ 代码相匹配。例如,您可以将成员函数添加到结构并从结构继承,如果结构和类位于不同的宇宙中,这是不可能的。

Stroustrup 的初衷是避免传统 C 风格“结构”阵营与 OO“类”人群之间的社区分裂。他还列举了只有一个概念而不是两个概念的好处。

【讨论】:

  • "它允许以更自然的方式将现有结构与 C++ 代码相匹配。例如,您可以将成员函数添加到结构 [..]"... 是的,这是我的问题:为什么它允许我们添加成员函数?我们已经为此上课了,对吧?
  • @Nawaz 它还允许向联合中添加成员函数。我们不能使用类来代替联合,因为它们的用途。
  • @Johannes Schaub:在“联合”的情况下,这是有道理的,因为“我们不能使用类来代替联合,因为它们的用途是”。完全有道理。但是结构呢?
  • 看来,减少压裂的更好解决方案是根本不创建class 关键字。无论如何,struct 的默认值要好得多。您可以在不提及任何访问说明符或 friend 声明的情况下创建有用的 struct,但您不能使用 class 这样做。如果您需要比所有公开内容更具体的内容,则无论您使用哪种构造,都必须将其拼写出来。
【解决方案2】:

从语言的角度来看,structuresunions 只是类的类型。如果概念更少(使用小写字母“c”),它会使语言规范更简单,并且它还可以减少指定语言的错误,因为如果必须拼出每个公共属性,就不太容易错过“明显”的东西对于每个结构联合和非结构、非联合类。

C++ 类比 C 结构具有许多潜在功能,但由于 C 结构可以被视为退化的 C++ 类,因此最简单的方法就是让它们完全如此。拥有一个特殊的 structure 概念和一个 class 概念并没有什么好处。

来自 ISO/IEC 14882:2003, 9 [类] / 4:

结构是一个用class-keystruct定义的类;默认情况下,它的成员和基类是公共的。 union 是使用 class-key union 定义的类;默认情况下,它的成员是公开的,并且一次只保存一个数据成员。

【讨论】:

  • 我喜欢这篇文章。来自我的 +1!
【解决方案3】:
  1. 为了与 C 兼容,需要结构字段的“public”默认值 可以访问结构字段的代码。
  2. 结构继承需要“public”默认值,以便子类 可以用来代替基础结构。
  3. 可以将结构变成与类不同的数据类型 (即不允许其中的访问类型说明符和方法),但这两者都是 编程不方便,给编译器增加了很多不必要的工作 开发人员。

【讨论】:

  • 我认为前两点在这里无关紧要,因为它不会试图回答我的问题。第 3 点,后半部分的陈述似乎并不属实。我们已经在 C 中使用过 struct。所以使用普通的 c-struct 一点也不方便!
  • 1-2 在那里,因为这些是必须为 class 添加新关键字的原因。我所说的“不方便”是指增量变化。即根据您的说法,当我想保护从 C 项目复制粘贴的结构的一个字段时,我必须将其重命名为 class 并将所有其他成员声明为 public,并可能修复所有继承。
【解决方案4】:

在 C 中,只有结构开始。面向对象始于设计库时,将指向这些结构的指针传递给依赖于该结构的一组库函数。 Win32 API 就是一个很好的例子。它不是 C++ 接口,而是 C 接口;但它仍然是面向对象的。

类在内存方面几乎与结构相同。成员函数不存储为类成员数据的一部分。它只是一个末尾带有额外函数指针的结构。所以一个类的函数表被解引用,就像 Windows API 使用面向对象一样,但是它封装了它,所以你看不到它。

继承、多态;谁在乎?人们对 C 很好,现在对 C 也很好。

【讨论】:

  • 校规:我也喜欢这篇文章。好帖子。 :-) +1 来自我!
  • school:请注意,额外的函数指针(vtable)仅在涉及虚函数时才需要。 “普通”成员函数是静态解析的,不需要额外的内存。
【解决方案5】:

允许你声明为结构的东西真正成为一个类,从而在创建 C 接口时实现类型安全。

您可以为您的 C 接口前向声明您的结构:

struct Foo;

你可以在上面声明方法

void doStuffThatModifiesFoo( struct Foo * foo, ... );
struct Bar getStuffFromFoo( const struct Foo * foo );

您也可以为它编写创建和销毁方法。

在下面,您不是将 Foo 实现为 C 结构,而是作为类实现,但您的 C 客户端不需要知道这一点。这比将其作为 void * 传递然后进行转换要好(如果有人将 void* 传递给完全不同的类型并进行转换,则不安全)。

【讨论】:

  • 严格来说,这不是 class-vs-struct 的事情。在纯 C 中也可以使用相同的技巧。
  • 但是当您在 C++ 中实现某些东西时它仍然很有帮助,但需要将类及其成员函数公开为具有全局函数的结构。
【解决方案6】:

“与 C 的兼容性”问题只意味着一个方向:旧的、有效的 C 代码也应该编译为 C++ 代码。一旦使用了只有 C++ 具有的任何语言特性,则反过来是不可能的。

这意味着在 C++ 中,你总是写类,你可以省略使用关键字struct ;尽管包括我在内的一些人认为它们可以派上用场,以表明一个类只是命名值的简单集合,没有真正的封装或可能的复杂行为。

【讨论】:

  • 许多现代 C++ 样式指南更喜欢使用 struct,因为它默认为 public,因此您可以先阅读 public 接口。
  • @Fabio:嗯,“很多”?我认为我从未见过任何风格指南建议过这一点。不过,出于您所说的原因,我倾向于在可以摆脱它的情况下这样做,但是我不记得在其他任何地方都推荐过它。有例子吗?
  • @jalf:我不知道他们有没有把它写下来,但它在 boost 代码中很常见。 LLVM 似乎只将它用于某些部分(模板?)。
  • @Fabio 没有什么可以阻止您从 class 定义中的公共接口开始。
猜你喜欢
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
  • 2021-05-12
  • 2011-08-01
  • 2011-12-26
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
相关资源
最近更新 更多