C++;举例说明虚拟性 我试图通过下面的例子来理解C++中的破坏行为:
该列表是否填满了所有可能的流程? 应该补充什么? 如何将给定的示例转换为短期 提出了“当基类的析构函数要进行多态操作时,总是使它们成为虚拟的。”这不包括场景4 <> Scott Meyers有效C++中的项目7:C++;举例说明虚拟性 我试图通过下面的例子来理解C++中的破坏行为: ,c++,virtual-destructor,C++,Virtual Destructor,该列表是否填满了所有可能的流程? 应该补充什么? 如何将给定的示例转换为短期 提出了“当基类的析构函数要进行多态操作时,总是使它们成为虚拟的。”这不包括场景4 Scott Meyers有效C++中的项目7: 如果一个类有任何虚函数,它应该有一个虚析构函数 未设计为基类或未设计为多态使用的类不应声明虚拟析构函数 它很轻(应该和不应该),并且与场景2对抗 使现代化 我改写了由伪码提供的C++标准:< /P> if static type of object is different from
- 如果一个类有任何虚函数,它应该有一个虚析构函数李>
- 未设计为基类或未设计为多态使用的类不应声明虚拟析构函数
我改写了由伪码提供的C++标准:< /P>
if static type of object is different from its dynamic type:
if the static type is a base class of the dynamic type:
if the static type has a virtual destructor:
We're fine - dynamic type's destructor will be called
else:
behavior is undefined [1]
else:
behavior is undefined [2]
[1] 代码将在没有警告的情况下编译,并且可能工作正常,但这并不能保证,并且可能会在运行时导致纠结错误
[2] 这很尴尬:
class A {};
class B {};
B *a = (B*)(new A());
delete a;
当您将这些方法声明为虚拟方法时,这意味着您正在指示编译器在处理派生类对象时应始终搜索该方法的派生版本。就这么简单。
在下面的示例中,若在基类方法中不使用virtual关键字,则将调用该方法的基类版本
#include <iostream>
class A
{
public:
virtual const char* fetchClassName() { return "A"; }
// this is a virtual destructor:
virtual ~A(){ cout<<"Destroying Base";}
};
class B: public A
{
public:
virtual const char* fetchClassName() { return "B"; }
virtual ~B(){ cout<<"Destroying Derive";}
};
int main(void)
{
B obj_b;
A &obj_a = obj_b;
std::cout << obj_a.fetchClassName() << "\n";
}
#包括
甲级
{
公众:
虚拟常量char*fetchClassName(){返回“A”;}
//这是一个虚拟析构函数:
virtual~A(){cout当您将方法声明为virtual时,这意味着您指示编译器在处理派生类对象时应始终搜索方法的派生版本。就这么简单。
在下面的示例中,若在基类方法中不使用virtual关键字,则将调用该方法的基类版本
#include <iostream>
class A
{
public:
virtual const char* fetchClassName() { return "A"; }
// this is a virtual destructor:
virtual ~A(){ cout<<"Destroying Base";}
};
class B: public A
{
public:
virtual const char* fetchClassName() { return "B"; }
virtual ~B(){ cout<<"Destroying Derive";}
};
int main(void)
{
B obj_b;
A &obj_a = obj_b;
std::cout << obj_a.fetchClassName() << "\n";
}
#包括
甲级
{
公众:
虚拟常量char*fetchClassName(){返回“A”;}
//这是一个虚拟析构函数:
virtual~A(){cout如果使用基指针销毁派生对象,而析构函数不是虚拟的,则最终会出现“未定义行为”的情况
N3690,5.3.5[解释删除]-3
在第一个备选方案(删除对象)中,如果
要删除的对象与其动态类型(静态)不同
类型应为待处理对象的动态类型的基类
已删除,静态类型应具有虚拟析构函数或
行为是未定义的
github存储库中给出的解释完全是错误的(“未调用派生析构函数,但未发生内存泄漏”)。您不能指望这一点
我没有阅读其余的内容,因为这会浪费时间。UB是UB…试图描述未定义的内容是胡说八道。当您使用基指针销毁派生对象,并且析构函数不是虚拟的时,您将陷入“未定义行为”的场景
N3690,5.3.5[解释删除]-3
在第一个备选方案(删除对象)中,如果
要删除的对象与其动态类型(静态)不同
类型应为待处理对象的动态类型的基类
已删除,静态类型应具有虚拟析构函数或
行为是未定义的
github存储库中给出的解释完全是错误的(“未调用派生析构函数,但未发生内存泄漏”)。您不能指望这一点
<>我没有读剩下的,因为这是浪费时间。UB是UB…试图描述未定义的废话。< /P>添加链接为什么它是未定义的行为。请@ PATEDEMIN:不幸的是,“官方”链接需要相当多的钱(C++标准,非常可悲,不是免费的)。。我已经添加了对我知道的上一份免费草稿的引用。感谢更新。我在回答中重新编写了这个复杂的规则。似乎这是我一直在寻找的通用短期。请添加一个链接,为什么它是未定义的行为。@peterdemin:不幸的是,“官方”链接需要很多钱(C++的标准,非常可悲,不是免费的)。我添加了一个引用,我知道最后一个自由可用的草稿。谢谢更新。我在回答中重复了这个复杂的规则。看起来,就像是普遍的短期,我在寻找。这个代码输出:B销毁派生的销毁基础。如果我在A~()之前删除虚拟。,结果保持不变。那么,您的观点是什么?当您不声明方法virtual时,会发生有趣的事情:)此代码输出:B销毁派生销毁基。如果我在~A()之前删除virtual,结果保持不变。那么,您的观点是什么呢?当您不声明方法虚拟时,会发生有趣的事情:)场景4永远不应该执行。您可以始终拥有一个“base”对象类作为成员而不是从中继承。场景2非常奇怪。可能永远不应该这样设计。好吧,谢谢你的设计说明。但我正在测试不同的虚拟函数组合是如何工作的,而不是设计概念。场景4永远不应该这样做。你可以始终拥有一个“base”对象类作为成员而不是从中继承。场景2非常奇怪。也许它永远不应该这样设计。好吧,谢谢你的设计说明。但是我在测试不同的虚拟函数组合是如何工作的,而不是设计概念。