虚拟函数的意外行为
Unexpected behaviour of virtual function?
当我用Visual Studio 2010运行以下C++代码时,如果任何派生类函数被声明为虚拟的,则程序会在删除变量时卡住。有人能解释一下吗?
void testInheritance()
{
class a
{
public :
char x;
void fn1()
{
std::cout<<"n In Class A Function 1 : "<<x;
}
virtual void fn2()
{
std::cout<<"n In Class A Function 2 : "<<x;
}
a()
{
x='A';
std::cout<<"n In A() : "<<x;
}
~a()
{
std::cout<<"n In ~A : "<<x;
}
};
class b: public a
{
public :
char y;
virtual void fn1()
{
std::cout<<"n In Class B Function 1 : "<<y;
}
void fn3()
{
std::cout<<"n In Class B Function 3 : "<<y;
}
b()
{
y='B';
std::cout<<"n In B() : "<<y;
}
~b()
{
std::cout<<"n In ~B : "<<y;
}
};
a* var = new b();
delete var;
}
更多信息:
我知道,要调用b::fn1和类b的析构函数,我需要在基类(即类a(中声明它们是虚拟的。但如果我不这样做,甚至不将类b中的任何函数(也不声明类a中的任何一个(声明为虚拟的,它应该同时调用a的fn1和析构函数。但是,当我声明b的任何成员(而不是a(为虚拟成员时,无论是新成员还是重载成员,当使用VS2010编译时,它都会挂起,当在linux上使用gcc4.4.4编译时,会中断。它本应该调用任意一个析构函数并正常工作,但我不明白程序崩溃的原因。
此外,当在VisualStudio2010中使用Intellitrace时,我试图在代码挂起的地方中断代码,我得到以下消息:
进程似乎处于死锁状态(或者没有运行任何用户模式代码(。所有线程都已停止。
由于您在程序中创建了未定义的行为,因此您预期会出现意外行为 使用指向具有 C++标准第1.3.24节规定: 允许的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行过程中以环境特征的记录方式行事(有或没有发布诊断消息(,再到终止翻译或执行(有诊断消息发布( 如何解决问题 基类中的析构函数应为虚拟的。non-virtual destructor
的base
类的指针删除derived
类对象会导致Undefined Behavior
。未定义的Beahavor意味着任何事情都可能发生。
您的析构函数不是虚拟的,因为您不允许将delete
var
作为基类指针。最有可能的是,根据其他虚拟函数的存在,您只得到了两组行为。
您需要声明析构函数虚拟
如果"stick"表示不调用b::~b()
,那么答案是a::~a()
需要是virtual
。
您正在使用基类(a
(指针来保存class b
的对象。当您delete var;
时,它只调用不是virtual
的a::~a()
;使其成为CCD_ 15;对CCD_ 16和CCD_。
[注意:另一种方式是,只有当你在某个地方放置了断点而没有通过时,它才能被击中。:(]
实际上,我已经受够了在C++测试中看到的东西,问在这种情况下会有什么行为。他们想让你回答,它会调用A的析构函数,但不会调用B的析构因子。
这不是有保证的行为,你不能依赖它。未定义的行为意味着你不能确定会发生什么,这里就是这样。
这也是一个"只是不要做…"的例子。在我的上一份工作中,我完全从测试这种行为的系统中删除了一个测试,理由是它无关紧要,偏离了主题。
使a
的析构函数成为虚拟的另一种选择是使其受到保护。这也将保护您,因为main()
将无法编译,因为您无法从那里调用delete var
。您甚至不能像main
那样调用b
中的未定义行为,因为您可能会感到惊讶,但delete
到a*
在那里也无法访问。
boost::shared_ptr<a>( new b );
安全地,因为它将为b而不是a创建一个deleter。
由于a
中有另一个虚拟函数,因此您几乎可以肯定地选择将其析构函数设为虚拟函数。
- C++析构函数被意外调用双链表
- 概念解析为使用 std::make_signed_t 时意外的函数模板
- 类中静态函数C++意外结果
- C++意外调用继承类的函数
- 模板函数意外的结果
- 在调用 std::bind 的产品后意外调用析构函数
- C++将派生类的const值传递给基意外行为的构造函数
- 移动构造函数的意外调用
- 使用类/函数模板组合进行意外诊断
- 函数调用中出现意外编译错误 (C++)
- 使用相同的函数时意外收到"std::out_of_range"错误
- 在第三个 pary 函数中使用矢量引用时出现意外错误
- C++ std::find() 寻址返回向量的类函数时的意外行为
- 基于范围的 std::move 调用意外复制构造函数
- 意外输出..函数绑定在虚拟表中的发生方式
- 在 c++ 中使用函数装饰器(使用闭包)时出现意外的分段错误
- C++中出现意外的编译错误:将默认值传递给函数参数
- 是什么导致了构造函数之后的这些"意外令牌"错误?
- 意外缺少隐式声明的复制/移动构造函数
- 在 winapi 回调函数上返回 FALSE 时出现意外行为(循环被跳过?