为什么工会不能在继承中使用? [英] Why union can't be used in Inheritance?

查看:65
本文介绍了为什么工会不能在继承中使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在c ++标准(第9.5/1节)中看到了以下内容:

I saw below thing in c++ standard (§9.5/1):

联合不得具有基类.工会不得用作基类.

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

工会可以具有成员职能(包括构造函数和析构函数),但不是虚拟的(10.3)功能

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

从上面,联合还可以具有构造函数和析构函数.

From above, union can have constructor and destructor as well.

那为什么在继承中不允许呢?

So why is it not allowed in Inheritance ?

用于回答评论:

  1. 如果允许联合作为基类,则派生类可以使用其数据.如果派生类只希望使用联合的一个成员,则可以使用这种方式来节省内存.我认为,这是不正确的继承.在这种情况下,在派生类内部具有联合会更好吗?

  1. 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具有多种类型的数据.众所周知,只能使用一种类型的数据.对于每种类型的数据,都有一个基类为该特定类型提供服务.在这种情况下,可以使用多重继承为Union中的所有类型的数据获取所有基类的服务.我也觉得这是对继承的不当使用.但是,在这一点上,有没有等同的概念可以实现内容?

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?

只是我的想法...

推荐答案

(此答案是针对C ++ 03编写的,自C ++ 11起情况可能有所改变)

(This answer was written for C++03, the situation may have changed since C++11)

我无法想象有任何令人信服的理由将其排除在外……更多的是,没有特别好的理由将其排除在外.工会的用途不那么重要,并且工会中成员的类型受到严格的限制,这些限制阻止了OO实践.这些限制-以及在联盟中手动跟踪具有有效性的特定变量的负担-几乎意味着您要对联盟进行的第一件事就是将其封装在一个类中,然后您仍然可以从该类继承.让联盟成为继承链的一部分只会分散痛苦.

I can't imagine any compelling reason for excluding it... more that there's no particularly good reason for including it. Unions just aren't used enough to matter that much, and there are heavy restrictions on the type of members in the union, restrictions that prevent OO practices. Those restrictions - and the burden of manually tracking the particular variable(s) in a union that have validity - mean pretty much the first thing you want to do with a union is encapsulate it in a class, then you can inherit from that anyway. Letting the union be part of the inheritance chain just spreads the pain around.

因此,任何可能使C ++临时用户产生的印象是,可以将联合体混入以OO为中心的代码中,这将带来多有麻烦的事情.工会本质上是一种用于内存保护,快速但讨厌的数据重新解释和实现变体的黑客,并且往往是一种实现细节,而不是一种接口细节.

So, anything that might give casual C++ users the impression that unions could be mixed into their OO-centric code would cause more trouble than good. Unions are basically a hack for memory conservation, fast-but-nasty data reinterpretation and implementing variants, and tend to be an implementation detail rather than an interface one.

您已通过编辑对问题进行了补充...随之而来的想法.

You've added a bit to your question with your edit... thoughts follow.

如果允许联合作为基类,则派生类可以使用其数据.如果派生类只希望使用联合的一个成员,则可以使用这种方式来节省内存.我认为,这是不正确的继承.在这种情况下,在派生类内部具有联合会更好吗?

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具有更少的封装它们的能力.如果它们是私有的,则可以很容易地成为类中的联合数据成员.

U's data members would either have to be - implicitly or explicitly - public, protected or private. If they're public or protected, then they're not encapsulated, and we're back in the "share the pain" scenario mentioned above. U has less ability to encapsulate them than a class containing a union. If they're private, then they could just as easily be a union data member in a class.

如果允许联合作为派生类,则它可以使用基类的服务.例如,如果Union具有多种类型的数据.众所周知,只能使用一种类型的数据.对于每种类型的数据,都有一个基类为该特定类型提供服务.在这种情况下,可以使用多重继承为Union中的所有类型的数据获取所有基类的服务.我也觉得这是对继承的不当使用.但是,在这一点上,有没有等同的概念可以实现内容?

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?

好的,这就是奇怪的地方.所以,我们得到了:

Ok, this is where things get weird. So, we've got:

union U : public A, private B { };

首先,让我更明确地说明一些事情.联合不能包含复杂的封装对象,它们是封装的对立面.您几乎只限于POD数据,并且不能具有非默认构造函数等.请注意,我在说的是联合的数据成员,而不是联合本身.因此,如果保留那些联合内容规则,则A和B将会非常有限,并且U派生的能力不是特别有用.

Firstly, let me be a bit more explicit about something. Unions can't contain complex, encapsulated objects - they're the antithesis of encapsulation. You're pretty much limited to POD data, and can't have non-default constructors etc.. Note I'm talking about the data members of the union, and not the union itself. So, A and B would - if those union-content rules remain - be very limited, and the ability of U to derive not particularly useful.

这就引出了一个问题,为什么联合不能以某种安全的方式管理更复杂的对象.好吧,他们怎么办呢?明显的答案是添加一个隐藏的枚举,以表明哪个有效,默认情况下应构造一些关于哪种类型的规则,在分配了不同的枚举字段时首先调用析构函数,等等,等等.也许它们应该抛出是否有人对当前未构造的成员执行某些操作?听起来还可以吗?

That leads into the question of why unions can't manage more complex objects in some safe way. Well, how could they do it? Obvious answer is add a hidden enum to say which one is valid, and some rules about which type should be constructed by default, invoking the destructor first when a different enum field is assigned to, etc etc etc.... Maybe they should throw if someone does something to the member that's not currently constructed? Sounds ok?

首先,枚举的开销可能不是必需的,因为客户端代码可能以已知的适当顺序使用一个成员,然后使用另一个成员.语言本身的检查和异常是类似的开销...如果留给客户端代码使用,则可以在多次使用之前将它们分解为一次检查.在这两种情况下,您都将为仅某些应用程序需要的一些管理开销付出代价-一种非常非C ++的方法.

Well, firstly, the overhead of an enum might not be necessary, as client code might use one member then another in a known-appopriate order. Checks and exceptions in the language itself are a similar overhead... they may be able to be factored down to a single check before multiple uses if left to the client code. In both cases, you'd be paying for some management overhead that only some applications need - a very un-C++ approach.

忽略这一点,工会并不是那么简单.像枚举一样,它们的使用被设计为灵活的,并且难以与编译器进行通信,因此可以对其进行清理,检查和自动化.您可能会认为枚举是复杂的吗?",但是每个枚举在概念上都是通用的,实际上是任意一组宽度可变的独立位域.描述哪些是互斥的或相互依存的等等并非易事.编译器根本不考虑问题空间.类似地,一个联合可以在同一数据上具有一个或多个并发合法视图,而其他视图则无效,并具有引导的微妙性.例如:将int64_t,double和char [4]的并集在设置为double以后始终可以读取为int64_t或char [4],但是相反,可能会读取无效的double并导致未定义的行为,除非您正在重新读取早些时候来自double的值,也许是在序列化/反序列化库中.编译器不想参与其中的管理,这是确保联合对象的成员遵守其自身封装中隐含的诺言所要做的事情.

Ignoring that, unions aren't that simple anyway. Like enums, their use is designed to be flexible and would be hard to communicate to the compiler so it could clean up, check and automate it. You might think "huh? enums are complex?", but each enum is - conceptually generalised - effectively an arbitrary set of independent bitfields of varying width. It's non-trivial to describe which ones are meant to be mutually exclusive or dependent etc.. The compiler doesn't buy into the problem space at all. Similarly, a union may have one or more concurrently legitimate views on the same data, while others are invalid, with subtleties to boot. For example: a union of int64_t, double, and char[4] could always be read as an int64_t or char[4] after being set as a double, but the other way around might read an invalid double and cause undefined behaviour, unless you're re-reading values that came from a double at some earlier time, perhaps in a serialisation/deserialisation library. The compiler doesn't want to buy into the management of that, which is what it would have to do to ensure object members of unions obeyed the promises implicit in their own encapsulation.

您问在派生类中加入联合会更好吗?" ...否-通常无法正常工作,因为大多数对象无法放入联合(请参见上文).无论联合是在派生类内部,还是通过假设的新语言功能,联合都实际上是派生类,您就遇到了这个问题.

You ask "is it better to have union inside derived class?"... no - doesn't generally work as most objects can't be put into a union (see above). You hit this problem whether the union is inside the derived class, or - through the new language features you postulate - the union actually is the derived class.

不过,我确实理解您的无奈.在实践中,人们有时确实想要任意非平凡对象的并集,因此他们使用重新解释强制转换或类似方法来破解它的繁琐方式,管理足够大的空间的内存对齐以支持他们将支持的对象集(或-更轻松但更慢-指向它们的指针).您会在boost变体和任何库中找到这种东西.但是,您不能从中得到……关于适当用法的知识,安全检查的范围等,都无法用C ++推论或表达出来.编译器不会为您这样做.

I do understand your frustration though. In practice, people do sometimes want unions of arbitrary non-trivial objects, so they hack it up the hard and dirty way using reinterpret cast or similar, managing memory alignment of some space big enough for the set of objects they'll support (or - easier but slower - a pointer to them). You'll find this sort of thing in the boost variant and any libraries. But, you can't derive from them... the knowledge about appropriate usage, the extent of safety checks etc. just isn't deducible or expressible in C++. The compiler's not about to do that for you.

这篇关于为什么工会不能在继承中使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆