7.3 联合

正如前面所看到的一样,在C++中,struct和class惟一的不同之处就在于,struct默认为public,而class默认为private。很自然地,也可以让struct有构造函数和析构函数。另外,一个union(联合)也可以带有构造函数、析构函数、成员函数甚至访问控制。在下面的例子中,还能再一次看到使用重载的好处。

7.3 联合 - 图1

从上面的代码中可以认为:union与class的惟一不同之处在于存储数据的方式(也就是说在union中int类型的数据和float类型的数据在同一内存区覆盖存放),但是union不能在继承时作为基类使用,从面向对象设计的观点来看,这是一种极大的限制(有关继承将在第14章中讨论)。

尽管成员函数使客户程序员对union的访问在一定程度上变得规范,但是,一旦union被初始化,仍然不能阻止他们选择错误的元素类型。例如在上面的程序中,即使不恰当,我们也可以写X.read_float(),然而,一个更安全的union可以封装在一个类中。在下面的例子中,注意enum是如何阐明代码的,以及重载是如何同构造函数一起出现的。

7.3 联合 - 图2

7.3 联合 - 图3

在上面的代码中,enum没有类型名(它是一个没有加标记的枚举),如果想立即定义enum的一个实例时,上面的这种做法是可取的。在这里以后没有必要涉及枚举的类型名,所以说,枚举的类型名是可选的,不是必须的。

union没有类型名和标识符。这叫做匿名联合(anonymous union),为这个union创建空间,但并不需要用标识符的方式和以点操作符(‘.’)方式访问这个union的元素。例如,如果匿名union是:

7.3 联合 - 图4

注意:我们访问一个匿名联合的成员就像访问普通的变量一样。惟一的区别在于:该联合的两个变量占用同一内存空间。如果匿名union在文件作用域内(在所有函数和类之外),则它必须被声明为static,以使它有内部的连接。

尽管SuperVar现在来说是安全的,但是,它的用途却有点值得怀疑,因为使用union的首要目的是为了节省空间,而增加vartype占用了union中很多与数据有关的空间。所以,节省的空间差不多就被抵消了。有两种选择可以使这种模式变得可行。如果vartype控制多个union实例—假如它们都是相同的数据类型—这样对于这一组实例,就仅仅只需要一个vartype,这样就不会占用更多的空间。一个更有效的方法是在所有vartype代码的前面加上#ifdef,这样就保证了在开发和测试中正确地使用。对于发行的代码,可以消除额外空间和时间开销。