c++ 为什么联盟不能用于继承?

我在c标准中看到下面的东西(§9.5/ 1):

A union shall not have base classes. A union shall not
be used as a base class.

A union can have member functions
(including constructors and
destructors), but not virtual (10.3)
functions

从上面可以看出,union可以具有构造函数和析构函数。

那么为什么不允许继承?

编辑:回答评论:

>如果union被允许作为基类,其数据可以由派生类使用。如果派生类有兴趣只使用一个联合成员,这样可以用来节省内存。我认为这是继承不当。在这种情况下,派生类内部的联合是否更好?
>如果union被允许作为派生类,它可以使用基类的服务。例如,如果联盟有多种类型的数据。我们知道,只能使用一种数据。对于每种类型的数据,存在基类以为该特定类型提供服务。在这种情况下,可以使用多重继承来获取Union中所有类型数据的所有基类的服务。这也是我觉得继承不当的使用。但是,在这一点上是否有任何等同的概念来实现内容?

只是我的想法…

(这个答案是为C 03写的,情况自C 11以来可能已经改变)

我无法想象有任何引人注目的理由排除它…更多的是没有特别好的理由来包含它。工会没有足够的重视,对联盟成员的类型有很大的限制,阻碍了OO做法的限制。这些限制 – 手动跟踪具有有效性的联盟中的特定变量的负担,这意味着您首先要使用联盟来将其封装在一个类中,那么您可以继承它。让工会成为继承链的一部分,只是传播痛苦。

所以,任何可能给偶然C用户的印象是,工会可以混合到他们的OO为中心的代码中会导致更多的麻烦而不是好的。工会基本上是内存保护,快速但令人讨厌的数据重新解释和实现变体的黑客,并且往往是一个实现细节而不是一个接口。

你已经添加了一些你的问题与你的编辑…想法遵循。

If union is allowed as a base class, its data can be used by a derived class. If derived class is interested to use only one member of union, this way can be used for saving memory. I think, this is improper inheritance. Is it better to have union inside derived class in that case ?

所以,我们正在讨论:

union U { int i; double d; };
struct D : U { };

U的数据成员将必须 – 隐式或明确 – 公开,受保护或私有。如果它们是公共的或受保护的,那么它们不被封装,并且我们回到上面提到的“分享痛苦”场景。 U比包含联合的类具有更少的封装能力。如果他们是私有的,那么他们可以很容易地成为一个类中的联合数据成员。

If union is allowed as derived class, it can use services of base class. For example, if Union has multiple types of data. As we know, only one type of data can be used. For each type of data, a base class is present to offer services for that particular type. In this case, multiple inheritance can be used to get services of all base classes for all types of data in Union. This also i feel as improper usage of inheritance. But is there any equivalent concept to achieve content in this point?

好的,这是事情变得奇怪的地方。所以我们有:

union U : public A, private B { };

首先,让我对某件事情更加明确。联盟不能包含复杂的封装对象 – 它们是封装的对立面。你几乎不受POD数据的限制,不能有非默认的构造函数等等。注意我在谈论联合的数据成员,而不是联盟本身。那么,如果这些工会内容规则仍然存在,那么A和B就会非常有限,而U的派生能力并不是特别有用。

这导致了为什么工会不能以某种安全的方式管理更复杂的对象的问题。那么他们怎么办呢?明确的答案是添加一个隐藏的枚举来说明哪一个是有效的,一些关于哪个类型应该被默认构造的规则,当一个不同的枚举字段被分配给等等时,首先调用析构函数….也许他们应该抛出如果有人对目前尚未建造的会员做某事?听起来不错

那么,首先,枚举的开销可能不是必需的,因为客户端代码可能使用一个成员,然后以已知的顺序使用另一个成员。语言本身的检查和异常是类似的开销…如果留给客户端代码,它们可以在多次使用之前被归结为单个检查。在这两种情况下,您都需要支付一些管理开销,只有一些应用程序需要 – 非常非C的方法。

不管怎样,工会不是那么简单。像枚举一样,它们的使用被设计为灵活的,并且很难与编译器进行通信,因此它可以清理,检查和自动化。你可能会认为“嗯?枚举是复杂的”,但是每个枚举都是概念上的泛化 – 有效地是一组随意变化的独立位域。描述哪些是相互排斥或依赖的,这是不重要的。编译器根本不会购买到问题空间。类似地,联合可以对同一数据具有一个或多个同时合法的视图,而另一些则是无效的,具有引导的微妙之处。例如:int64_t,double和char [4]的并集在被设置为double之后总是可以被读取为int64_t或char [4],但是另一个方法可能会读取一个无效的double并导致未定义的行为,除非您可以在早些时候重新读取来自双倍的值,也许在序列化/反序列化库中重新读取值。编译器不想购买管理,这样做是为了确保工会的对象成员遵守自己封装中隐含的承诺。

你问“派生类内部联合是否更好?”…否 – 通常不能工作,因为大多数对象不能被放入工会中(见上文)。你会碰到这个问题,无论联合是否在派生类中,或者 – 通过你假设的新语言功能 – 实际上是派生类。

我明白你的沮丧。在实践中,人们有时会想要工会的任意非平凡的对象,所以他们使用重新插入或类似的方式将它们狠狠地打破了这些困难和肮脏的方式,管理一些空间足够大的内存对齐,以便他们支持的对象集(或 – 更容易但更慢 – 指向他们的指针)。你会发现这种事情在boost变种和任何图书馆。但是,您不能从他们那里获得…关于适当使用的知识,安全检查的程度等等在C中不可推导或表达。编译器不会为你做这个。

翻译自:https://stackoverflow.com/questions/3615001/why-union-cant-be-used-in-inheritance

转载注明原文:c++ 为什么联盟不能用于继承?