C++如何将抽象基类Drawable的子类存入容器实现多态调用?
解决方案
核心原理
C++容器直接存储对象时,会在容器的连续内存空间中直接构造对应类型的实例。你声明std::vector<Drawable>时,容器所有元素的内存分配、拷贝逻辑都会按照基类Drawable的大小和类型处理,除了抽象类无法实例化的报错外,就算基类可实例化也会出现对象切片问题,丢失子类特有成员,导致多态完全失效。
要实现多态容器,必须存储基类的指针/智能指针,由指针指向堆上分配的子类实例,保留多态特性。
修改步骤
- 将容器类型改为存储智能指针,优先使用
std::unique_ptr(独占所有权场景),需要多所有者共享的场景可以用std::shared_ptr - 修复子类
Square重复定义name成员的bug:子类不需要重复定义基类已有的成员,否则你在构造函数中赋值的是子类独有的name,基类name始终为空,会导致之前写的operator==判断完全失效 - 插入元素时直接构造子类实例的智能指针存入容器
- 遍历容器时调用
draw()即可自动触发多态
修复后可运行代码
#include <vector> #include <string> #include <memory> // 引入智能指针头文件 struct Drawable { public: std::string name; virtual void draw() = 0; Drawable() = default; virtual ~Drawable() = default; Drawable(const Drawable &other) = default; // 拷贝构造补充const符合通用规范 Drawable(Drawable &&other) = default; Drawable &operator=(const Drawable &other) = default; Drawable &operator=(Drawable &&other) = default; }; bool operator==(const Drawable &lhs, const Drawable &rhs) { return lhs.name == rhs.name; } bool operator!=(const Drawable &lhs, const Drawable &rhs) { return !(lhs == rhs); } struct Square : public Drawable { Square(std::string name) { this->name = std::move(name); } void draw() override // 加override关键字显式标记重写,编译期就能检查出函数签名写错的问题 { /* 业务逻辑 */ } }; int main() { std::vector<std::unique_ptr<Drawable>> drawables; // 构造子类实例的智能指针存入容器 drawables.push_back(std::make_unique<Square>("reddy")); // 可继续添加其他Drawable子类的实例 // drawables.push_back(std::make_unique<Circle>("blue_circle")); // 遍历统一调用draw,自动触发多态 for (auto &item : drawables) { item->draw(); } }
搜索方向补充
你之前没找到相关教程是关键词选择的问题,搜索C++ 多态容器、C++ 抽象类 存储到容器、C++ 对象切片就可以找到对应的讲解内容。
内容的提问来源于stack exchange,提问作者user2393256
相关产品推荐
相关产品推荐

