class Student{ public: Student(bool g, int a): gender(g), age(a) {} private: bool gender; int age; }; union T{ Student s; // 含有非POD类型的成员,gcc-5.1.0 版本报错 char name[10]; }; int main(){ return 0; }上面的代码中,因为 Student 类带有自定义的构造函数,所以是一个非 POD 类型的,这导致编译器报错。这种规定只是 C++ 为了兼容C语言而制定,然而在长期的编程实践中发现,这种规定是没有必要的。
关于 POD 类型稍后我们会讲解,大家先不要着急。
接下来,我们具体看一下 C++11 对 C++98 的改进。
class B1{};
class B2 : B1 { B1 b; };
class B1 { static int n; };
class B2 : B1 { int n1; };
class B3 : B2 { static int n2; };
union U { static int func() { int n = 3; return n; } };需要注意的是,静态成员变量只能在联合体内定义,却不能在联合体外使用,这使得该规则很没用。
#include <string> using namespace std; union U { string s; int n; }; int main() { U u; // 构造失败,因为 U 的构造函数被删除 return 0; }在上面的例子中,因为 string 类拥有自定义的构造函数,所以 U 的构造函数被删除;定义 U 的类型变量 u 需要调用默认构造函数,所以 u 也就无法定义成功。
#include <string> using namespace std; union U { string s; int n; public: U() { new(&s) string; } ~U() { s.~string(); } }; int main() { U u; return 0; }构造时,采用 placement new 将 s 构造在其地址 &s 上,这里 placement new 的唯一作用只是调用了一下 string 类的构造函数。注意,在析构时还需要调用 string 类的析构函数。
new(address) ClassConstruct(...)
address 表示已有内存的地址,该内存可以在栈上,也可以在堆上;ClassConstruct(...) 表示调用类的构造函数,如果构造函数没有参数,也可以省略括号。
union U{
union { int x; }; //此联合体为匿名联合体
};
#include <cstring> using namespace std; class Student{ public: Student(bool g, int a): gender(g), age(a){} bool gender; int age; }; class Singer { public: enum Type { STUDENT, NATIVE, FOREIGENR }; Singer(bool g, int a) : s(g, a) { t = STUDENT; } Singer(int i) : id(i) { t = NATIVE; } Singer(const char* n, int s) { int size = (s > 9) ? 9 : s; memcpy(name , n, size); name[s] = '\0'; t = FOREIGENR; } ~Singer(){} private: Type t; union { Student s; int id; char name[10]; }; }; int main() { Singer(true, 13); Singer(310217); Singer("J Michael", 9); return 0; }上面的代码中使用了一个匿名非受限联合体,它作为类 Singer 的“变长成员”来使用,这样的变长成员给类的编写带来了更大的灵活性,这是 C++98 标准中无法达到的(编译器会报
member 'Student Singer::<anonymous union>::s' with constructor not allowed in union
错误)。本文链接:http://task.lmcjl.com/news/18572.html