Sho*_*out 18 c++ inheritance virtual-functions
我有名为“Base”和“Derived”的类。
struct Base {
Base() = default;
virtual ~Base() = default;
Base(const Base&) = delete;
Base& operator=(const Base&) = delete;
virtual void DoStuff() = 0;
};
Run Code Online (Sandbox Code Playgroud)
“Base”类需要虚拟析构函数,这是可以理解的。我也不允许复制这个类
struct Derived : Base {
Derived() = default;
~Derived() override = default;
void DoStuff() override { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)
int main()
{
std::shared_ptr<Base> a = std::make_shared<Derived>();
a->DoStuff();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在让我们介绍一下其他的类,我不知道,Callable还有DerivedCallable
struct Callable
{
virtual void Call() = 0;
};
Run Code Online (Sandbox Code Playgroud)
struct DerivedCallable : Base, Callable
{
DerivedCallable() = default;
~DerivedCallable() override = default;
void DoStuff() override { /*...*/ }
void Call() override { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)
int main()
{
std::shared_ptr<Base> a = std::make_shared<Derived>();
a->DoStuff();
{
auto callableA = std::dynamic_pointer_cast<DerivedCallable>(a);
if(callableA) {
callableA->Call();
}
}
std::shared_ptr<Base> b = std::make_shared<DerivedCallable>();
b->DoStuff();
{
auto callableB = std::dynamic_pointer_cast<DerivedCallable>(b);
if(callableB) {
callableB->Call();
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Derived不继承自Callable,callableAnullptr 也是如此,因此 if 语句不会执行该Call()函数。
DerivedCallable另一方面,继承自Callable,std::dynamic_pointer_cast会将对象的引用计数增加到 2,因此当callableB超出范围时,对象不会被释放,只有引用计数会减少到 1,然后 main 函数才会释放b。
是否Callable需要有一个虚拟析构函数?
Art*_*yer 19
如果要通过基类指针删除派生类对象,则只需要虚拟析构函数。
由于您使用的是std::shared_ptr,因此不需要任何虚拟析构函数,因为共享指针存储类型正确的删除器(无论您如何转换它)。
如果您要拥有一个DerivedCallable带有指针的对象Callable(或调用astd::unique_ptr<Callable>的其他对象),那么它应该有一个虚拟析构函数。但是,如果您只拥有 的非拥有引用,那么您并不严格需要虚拟析构函数。deleteCallable*Callable*
当类已经有其他虚拟成员时添加虚拟析构函数非常便宜,因此添加它就可以了,这样您就不必担心意外地delete出错。
这取决于。理论上,Base不需要虚拟析构函数。当您拖拽一个动态类型与其静态类型不同的对象时,您需要一个虚拟的析构函数。
在您的示例中,您有Base真正指向Derivied对象的指针。如果您不打算创建~Base()虚拟对象,那么销毁该对象将表现出未定义的行为 - 可能是无法销毁Derived该对象的一部分。
因此,只要您不打算通过特定基类拥有指向对象的(拥有!)指针,该基类的析构函数就不必是虚拟的。
| 归档时间: |
|
| 查看次数: |
1221 次 |
| 最近记录: |