向std::vector存入子类实例,为何调用父类虚方法而非子类?
问题原因与解决方案
问题根源:对象切片
你遇到的是C++里典型的对象切片问题。
当执行v.push_back(Child())时,vector<Parent>只能存放Parent类型的对象。此时编译器会把Child对象中属于Parent的部分拷贝到vector元素中,而Child类独有的数据、虚函数表中指向Child::Test的指针等信息都会被“切掉”。最终vector里存储的只是一个纯粹的Parent对象,调用Test()自然会执行父类的版本。
解决方案:存储指针/智能指针
要保留多态行为,不能直接存储对象实例,得存储指向基类的指针或智能指针。这样vector里的指针会指向完整的子类对象,虚函数机制就能正常工作,调用对应子类的方法。
修改后的示例代码(用智能指针)
#include <iostream> #include <vector> #include <memory> class ParentAbstract { public: virtual void Test() = 0; virtual ~ParentAbstract() = default; // 必须添加虚析构,防止内存泄漏 }; class Parent : public ParentAbstract { public: void Test() override { std::cout << "parent" << std::endl; } }; class Child : public Parent { public: void Test() override { std::cout << "child" << std::endl; } }; int main() { std::vector<std::unique_ptr<ParentAbstract>> v; v.push_back(std::make_unique<Child>()); v.at(0)->Test(); // 输出:child }
关键点说明
- 使用
std::unique_ptr(或std::shared_ptr)管理对象生命周期,避免手动释放指针的麻烦和内存泄漏。 - 基类
ParentAbstract必须添加虚析构函数,这样智能指针销毁对象时,会正确调用子类的析构函数,完成完整的资源清理。 - 用
override关键字显式标记重写的虚函数,能让编译器帮你检查是否正确重写了父类的虚方法,避免拼写错误等问题。
内容的提问来源于stack exchange,提问作者Kayla
相关产品推荐
相关产品推荐

