C++中如何让类接受其属性类的子类作为参数?
解决类接受其父类子类作为属性的问题
原代码的核心问题是对象切片:当按值传递子类对象给接受基类的函数时,仅会复制基类部分,丢失子类特有的成员数据,无法保留多态特性。
正确实现方案
要支持多态地存储子类对象,需通过指针或引用操作,推荐使用智能指针管理生命周期:
- 基类添加虚析构函数:确保通过基类指针销毁子类对象时能正确调用子类析构函数,避免未定义行为。
- 用智能指针存储属性:在
B中使用std::unique_ptr<A>替代A的实例,保留子类对象的完整信息。 - 优化构造函数:提供直接接受智能指针的构造函数,或添加模板构造函数简化子类对象的传入流程。
修正后的代码
#include <memory> #include <iostream> class A { public: virtual ~A() = default; // 必须的虚析构函数 virtual void show() const = 0; // 纯虚函数,让A成为抽象类(可选但推荐) }; class B : public A { std::unique_ptr<A> a; public: // 直接接受unique_ptr<A>的构造函数 explicit B(std::unique_ptr<A> ptr) : a(std::move(ptr)) {} // 模板构造函数:自动包装任意A的子类 template <typename Derived, typename... Args> explicit B(Args&&... args) : a(std::make_unique<Derived>(std::forward<Args>(args)...)) {} void show() const override { a->show(); // 调用子类的show方法 } }; class C : public A { int i; public: explicit C(int i) : i(i) {} void show() const override { std::cout << "C类实例,值为:" << i << std::endl; } }; // 可以添加更多A的子类,比如D class D : public A { std::string s; public: explicit D(std::string s) : s(std::move(s)) {} void show() const override { std::cout << "D类实例,字符串为:" << s << std::endl; } }; int main() { // 方式1:使用模板构造函数直接传入子类构造参数 B b1(std::make_unique<C>(1)); // 更简洁的方式(通过模板构造函数) B b2(2); // 自动创建C(2)并包装为unique_ptr<A> B b3("hello"); // 自动创建D("hello") // 演示多态行为 b1.show(); // 输出:C类实例,值为:1 b2.show(); // 输出:C类实例,值为:2 b3.show(); // 输出:D类实例,字符串为:hello return 0; }
关键说明
- 虚析构函数:基类
A的虚析构函数是多态销毁的必要条件,否则会导致子类资源泄漏。 - 智能指针:
std::unique_ptr自动管理内存,无需手动释放,避免内存泄漏风险。 - 模板构造函数:简化了
B的实例化过程,无需手动创建智能指针,直接传入子类的构造参数即可。 - public继承:原代码默认的private继承会导致子类无法被视为基类的公开派生类,改为public继承才能正确使用多态。
内容的提问来源于stack exchange,提问作者Aboody13
相关产品推荐
相关产品推荐

