C++11 联合包含具有虚函数的数据成员
c++11 union contains data member with virtual function
#include <iostream>
class derive1{
public:
derive1() = default;
~derive1() = default;
virtual void func() { std::cout << "derive 1" << std::endl; }
};
class derive2 {
public:
derive2() = default;
~derive2() = default;
virtual void func() { std::cout << "derice 2" << std::endl; }
};
union classUnion {
classUnion() {};
~classUnion() {};
derive1 obj1;
derive2 obj2;
};
int main() {
classUnion u1;
u1.obj1.func(); // <-- OK print 'derive 1'
derive1 &dev1 = u1.obj1;
dev1.func(); // <-- OK print 'derive 1'
derive1 *ptr = &(u1.obj1);
ptr->func(); // <-- core dump/seg fault
return 0;
}
我认为 C++11 允许非平凡的构造函数(具有虚函数(。我看不出这里有什么问题。我使用 "g++ -std=c+11 test.cpp"来编译它(GCC 4.8 和 GCC 5.0(。
问题是你从不初始化联合中的对象。至少,使其工作的最简单方法是以下小调整:
union classUnion {
classUnion() {};
~classUnion() {};
derive1 obj1={}; // unions can have one inline initializer
derive2 obj2;
};
但是,如果您改为这样做:
int main() {
classUnion u1;
u1.obj1 = derive1{};
...
}
它仍然会崩溃。原因是因为您要赋值到一个未初始化的对象中,特别是您有一个用户定义的析构函数(即虚拟析构函数(。
请考虑以下事项:(http://en.cppreference.com/w/cpp/language/union。
如果联合的成员是具有用户定义的构造函数的类,并且 析构函数,用于切换活动成员、显式析构函数和 通常需要新的放置:
因此,要实际使用具有虚函数(通常需要虚拟析构函数(的类,您将需要使用放置新调用和手动销毁调用,如下所示:
int main() {
classUnion u1;
new (&u1.obj1) derive1{};
... // use obj1
u1.obj1.~derive1();
new (&u1.obj2) derive2{};
... // use obj2
u1.obj2.~derive2();
}
示例中对
func()
的调用都不是正常的,它们都是未定义的行为。union
不会默认初始化其任何成员;如果要这样做,它将初始化哪一个?
为了演示这一点,请添加一个非静态数据成员derive1
并在 func()
中打印它,您将看到垃圾值,或者您的程序将更早崩溃。
class derive1{
public:
derive1() = default;
~derive1() = default;
virtual void func() { std::cout << "derive 1 " << i << std::endl; }
int i = 20;
};
现场演示
若要修复示例,请将 union
构造函数更改为在 mem 初始值设定项列表中构造obj1
classUnion() : obj1() {};
或为obj1
添加大括号或等于初始值设定项
derive1 obj1 = {};
至于为什么在您的示例中对func()
的前 2 次调用似乎有效,我猜 gcc 内联了这些函数调用,但在处理 derived1 *
时没有这样做,这导致最后一次调用失败。
相关文章:
- 如何在c++中定义以struct为数据成员的类中的构造函数
- 友元函数无法访问私有数据成员 (c++)
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 在 C++ 中,默认情况下构造函数为类的数据成员提供的值是多少?
- 错误: 无效使用非静态数据成员"应用程序::应用程序构造函数"
- "Class1"类"Class2"对象作为私有数据成员。如何通过"Class 2"函数引用"Class1"对象?
- 如何将结构数据成员传递到函数中
- 构造函数正在初始化数据成员
- 使用 lambda 函数初始化静态数据成员
- 是否可以访问类数据成员并在析构函数中对它们执行操作?
- 学习C++并在早期示例中遇到错误(在非静态数据成员之前需要构造函数)
- 初始化数据成员取决于构造函数中的条件
- 返回带有另一个类的数据成员的构造函数?遇到转换错误?
- Getter 函数,用于在 2d 数组是类的数据成员时检索 2d 数组元素
- "非静态数据成员之前需要构造函数" - 我是否使用"boost::variant"
- 我们可以直接为任何数据成员赋值. 为什么要使用构造函数?
- 没有数据成员和大括号语法的类的默认复制构造函数
- 当使用嵌套类功能时,使用非静态数据成员的使用无效,但是当函数未固定时可以
- 将数据成员的指针传递给基类构造函数是否安全?
- 无法访问派生类函数内的基类的受保护数据成员