C++ c++;11 union包含具有虚拟函数的数据成员 #包括 派生类1{ 公众: derive1()=默认值; ~derive1()=默认值; virtual void func(){std::cout
问题在于您从未初始化联合内部的对象。至少,使其工作的最简单方法是以下小调整:C++ c++;11 union包含具有虚拟函数的数据成员 #包括 派生类1{ 公众: derive1()=默认值; ~derive1()=默认值; virtual void func(){std::cout,c++,c++11,unions,C++,C++11,Unions,问题在于您从未初始化联合内部的对象。至少,使其工作的最简单方法是以下小调整: #include <iostream> class derive1{ public: derive1() = default; ~derive1() = default; virtual void func() { std::cout << "derive 1" << std::endl; } }; class derive2 { public:
#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;
}
但是,如果您改为这样做:
union classUnion {
classUnion() {};
~classUnion() {};
derive1 obj1={}; // unions can have one inline initializer
derive2 obj2;
};
它仍然会崩溃。原因是您正在分配到一个未初始化的对象,特别是您有一个用户定义的析构函数(即虚拟析构函数)
考虑以下几点:
()
如果联合的成员是具有用户定义构造函数和
析构函数,切换活动成员,显式析构函数和
通常需要新的安置:
因此,要实际使用带有虚拟函数的类(通常需要虚拟析构函数),需要使用新的和手动的销毁调用,如下所示:
int main() {
classUnion u1;
u1.obj1 = derive1{};
...
}
在您的示例中,对
func()
的调用都不正常,它们都是未定义的行为。union
不会默认初始化其任何成员;如果要这样做,它会初始化哪个成员
为了演示这一点,将非静态数据成员添加到derive1
并在func()
中打印它,您将看到垃圾值,或者您的程序将更早崩溃
int main() {
classUnion u1;
new (&u1.obj1) derive1{};
... // use obj1
u1.obj1.~derive1();
new (&u1.obj2) derive2{};
... // use obj2
u1.obj2.~derive2();
}
或者为obj1
classUnion() : obj1() {};
至于为什么在您的示例中对
func()
的前两个调用似乎有效,我猜gcc将这些函数调用内联,但在处理derived1*
时它没有这样做,这导致最后一个调用失败。您从未构造过任何东西。C++11允许非平凡的构造函数,但必须手动调用它们(编译器本身无法知道您要“激活”的联合成员”)=
不起作用,因为您正在对一个不存在的对象调用成员函数。@t.C.有趣的是,我在您发表评论的那一刻修改了我的猜测。是的,我想就是这样。我想我可以修改答案以减少它的推测性。
classUnion() : obj1() {};
derive1 obj1 = {};