C++子类的智能指针赋值给父类的智能指针,析构函数不是虚函数,也能正确执行析构
正如大家都知道,如下代码片段:
BaseNode *pp1 = new BinaryTreeNode(); // BaseNode 是 BinaryTreeNode的父类
delete pp1;
如果想要在delete回收pp1指针时正确析构对象,即:先执行BinaryTreeNode()函数,再执行BaseNode()函数。我们需要在BaseNode类中将~BaseNode()函数定义为虚函数。如下所示:
class BaseNode {
public:
BaseNode();
virtual ~BaseNode();
};
class BinaryTreeNode : public BaseNode {
public:
virtual ~BinaryTreeNode();
};
int main() {
cout << "使用裸指针" << endl;
BaseNode *pp1 = new BinaryTreeNode();
delete pp1;
return 0;
}
BaseNode::BaseNode() {}
BaseNode::~BaseNode() {
cout << "~BaseNode" << endl;
}
BinaryTreeNode::~BinaryTreeNode() {
cout << "~BinaryTreeNode" << endl;
}
执行结果:
使用裸指针
~BinaryTreeNode
~BaseNode
如我们所愿,在将~BaseNode()函数定义为虚函数后,析构函数正确执行。
如果~BaseNode()函数不是虚函数,使用智能指针shared_ptr。在指针析构的时候是否析构函数正确执行呢?
实验的代码如下:
class BaseNode {
public:
BaseNode();
~BaseNode();
};
class BinaryTreeNode : public BaseNode {
public:
~BinaryTreeNode();
};
int main() {
{
cout << "使用智能指针" << endl;
std::shared_ptr<BaseNode> p1;
p1 = std::shared_ptr<BinaryTreeNode>(new BinaryTreeNode());
}
cout << "使用裸指针" << endl;
BaseNode *pp1 = new BinaryTreeNode();
delete pp1;
return 0;
}
BaseNode::BaseNode() {}
BaseNode::~BaseNode() {
cout << "~BaseNode" << endl;
}
BinaryTreeNode::~BinaryTreeNode() {
cout << "~BinaryTreeNode" << endl;
}
结果如下:
使用智能指针
~BinaryTreeNode
~BaseNode
使用裸指针
~BaseNode
可以看出使用智能指针时,即便父类的析构函数不是虚函数,也能够正确析构。
注意:
虽然智能指针能够在父类析构函数不是虚函数的情况之下正确析构,但实际使用过程中如果遇到“子类指针要赋值给父类”的情况,最好将父类的析构函数定义为虚函数。除非你的代码对性能要求非常高,你需要仔细衡量一下,因为定义虚函数会引入的虚函数表,不仅会增加编译后的文件的大小,也会因为每次实例化该对象都会额外分配虚函数表的内存空间,增加内存消耗。