std::shared_ptr 可调用父类的非虚析构函数

 1 struct IBase
 2 {
 3     IBase() {
 4         std::cout << "IBase::IBase()" << std::endl;
 5     }
 6     virtual ~IBase() {
 7         std::cout << "IBase::~IBase()" << std::endl;
 8     }
 9     virtual void execute() = 0;
10 };
11 using IBaseSP = std::shared_ptr<IBase>;
12 using IBaseUP = std::unique_ptr<IBase>;
13 
14 class Foo : public IBase
15 {
16 public:
17     Foo() {
18         std::cout << "Foo::Foo()" << std::endl;
19     }
20     ~Foo() override {
21         std::cout << "Foo::~Foo()" << std::endl;
22     }
23     void execute() override {
24         std::cout << "Foo::execute()" << std::endl;
25     }
26 };
27 
28 class Bar : public IBase
29 {
30 public:
31     Bar() {
32         std::cout << "Bar::Bar()" << std::endl;
33     }
34     ~Bar() override {
35         std::cout << "Bar::~Bar()" << std::endl;
36     }
37     void execute() override {
38         std::cout << "Bar::execute()" << std::endl;
39     }
40 };
 1 int main() {
 2     IBase* p = new Foo();
 3     p->execute();
 4     delete p;
 5 
 6     std::cout << "----------" << std::endl;
 7 
 8     std::queue<IBaseUP> queueUP;
 9     {
10         queueUP.push(std::make_unique<Foo>());
11         queueUP.push(std::make_unique<Bar>());
12     }
13 
14     while (!queueUP.empty()) {
15         auto &p = queueUP.front();
16         p->execute();
17         queueUP.pop();
18     }
19 
20     std::cout << "----------" << std::endl;
21 
22     std::queue<IBaseSP> queueSP;
23     {
24         queueSP.push(std::make_shared<Foo>());
25         queueSP.push(std::make_shared<Bar>());
26     }
27 
28     while (!queueSP.empty()) {
29         auto &p = queueSP.front();
30         p->execute();
31         queueSP.pop();
32     }
33 
34     return 0;
35 }

本测试环境为VS2015。支持C++11标准。

一般的我们通过指针或引用在C++中实现多态。如果要把数据存入容器,则可以使用智能指针。

如果要确保对象可以正常析构,则需要将父类的析构函数声明为虚函数。这样通过父类指针delete时,可确保子类对象的析构函数被正常调用。

正常情况下的执行结果如下图所示,父类及子类的析构函数都可以被调用:

如果父类的析构函数不是虚函数,则结果如下图:

可以看到,只有父类的析构函数被调用了。子类的析构函数并没有被调用,则产生错误。

这一点上,对于原始的指针或者std::unique_ptr。其表现是一致的。也符合C++基本的语法。

但是对于std::shared_ptr。即便父类析构函数并非虚函数,其子类的析构函数依然可以被调用。

对于此种行为的原因尚未查明(待更新)。也许这是std::shared_ptr专门设计的一种特性。但为谨慎起见,我们也未必需要此特性。

C++11中引入了新的关键字“override”。对于子类中要实现多态(即要对父类方法进行override)的方法。在函数定义中使用override关键子,则编译器会帮助检测语法错误。如果父类方法未声明virtual则报错,提升代码质量。

如果使用了override关键字,则可不必在函数开头声明virtual。

原文地址:https://www.cnblogs.com/waterfall/p/10173478.html