如何实现非模板Aquarium类存储泛型模板Fish子类?
解决方案
核心问题分析
原代码中Fish<T>是模板类,不同T对应的Fish<T>是完全独立的类型,无法直接存入同一容器。因此必须先抽离出非模板的抽象基类,让所有鱼类共享统一接口,这样非模板的Aquarium才能通过多态指针存储各类鱼。
问题解答
存储方式
- 定义非模板抽象基类
AbstractFish,包含所有鱼类的公共虚接口(如swim()、虚析构函数); - 让原模板类
Fish<T>继承AbstractFish,保留其特有的模板逻辑; - Aquarium内部使用
std::vector<std::shared_ptr<AbstractFish>>存储鱼类,借助智能指针自动管理内存,同时支持多态调用。
- 定义非模板抽象基类
addFish/removeFish的参数与返回值
addFish:实现为模板方法,参数接受std::shared_ptr<FishDerived>(任意Fish派生类的智能指针),通过向上转换存入容器;removeFish:提供两种版本:- 模板版本:返回指定类型的
std::shared_ptr<FishDerived>,通过dynamic_pointer_cast做类型安全检查; - 基类版本:返回
std::shared_ptr<AbstractFish>,适用于不需要具体类型的场景。
- 模板版本:返回指定类型的
完整实现代码
#include <iostream> #include <vector> #include <memory> #include <stdexcept> // 非模板抽象基类:所有鱼类的统一接口 class AbstractFish { public: virtual ~AbstractFish() = default; virtual void swim() const = 0; virtual void breathe() const { std::cout << "Fish is breathing." << std::endl; } }; // 模板化Fish类,继承自AbstractFish template<typename T> class Fish : public AbstractFish { public: void breathe() const override { std::cout << "Fish<T> is breathing with value = " << T{} << std::endl; } }; // 模板化Salmon类 template<typename T> class Salmon : public Fish<T> { public: void swim() const override { std::cout << "Salmon is swimming with value = " << T{} << std::endl; } }; // 模板化Goldfish类 template<typename T> class Goldfish : public Fish<T> { public: void swim() const override { std::cout << "Goldfish is swimming with value = " << T{} << std::endl; } }; // 非模板化Aquarium类 class Aquarium { private: std::vector<std::shared_ptr<AbstractFish>> fishTank; public: // 添加任意类型的鱼 template<typename FishDerived> void addFish(std::shared_ptr<FishDerived> fish) { fishTank.push_back(std::static_pointer_cast<AbstractFish>(fish)); } // 移除并返回指定类型的第一条鱼 template<typename FishDerived> std::shared_ptr<FishDerived> removeFish() { for (auto it = fishTank.begin(); it != fishTank.end(); ++it) { auto derivedFish = std::dynamic_pointer_cast<FishDerived>(*it); if (derivedFish) { fishTank.erase(it); return derivedFish; } } throw std::runtime_error("该类型的鱼不存在"); } // 移除并返回任意一条鱼 std::shared_ptr<AbstractFish> removeAnyFish() { if (fishTank.empty()) { throw std::runtime_error("水族箱是空的"); } auto fish = fishTank.back(); fishTank.pop_back(); return fish; } // 让所有鱼游泳 void makeFishSwim() { for (const auto& fish : fishTank) { fish->swim(); } } // 获取当前鱼的数量 size_t getFishCount() const { return fishTank.size(); } }; int main() { Aquarium aquarium; // 创建不同类型的鱼 auto salmonInt = std::make_shared<Salmon<int>>(); auto goldfishDouble = std::make_shared<Goldfish<double>>(); auto salmonString = std::make_shared<Salmon<std::string>>(); // 添加到水族箱 aquarium.addFish(salmonInt); aquarium.addFish(goldfishDouble); aquarium.addFish(salmonString); std::cout << "所有鱼开始游泳:" << std::endl; aquarium.makeFishSwim(); // 移除一条Salmon<int> auto removedSalmon = aquarium.removeFish<Salmon<int>>(); std::cout << "\n移除了Salmon<int>,剩余鱼数量:" << aquarium.getFishCount() << std::endl; // 移除任意一条鱼 auto removedAny = aquarium.removeAnyFish(); std::cout << "移除了一条鱼,剩余鱼数量:" << aquarium.getFishCount() << std::endl; return 0; }
关键细节说明
- 抽象基类的作用:
AbstractFish是实现多态的核心,让不同模板实例的鱼类能被统一管理; - 智能指针选型:
std::shared_ptr自动处理对象生命周期,避免手动内存管理的风险; - 类型转换安全:
static_pointer_cast用于安全的向上转换,dynamic_pointer_cast在向下转换时做类型校验,确保移除操作的类型安全; - 接口灵活性:同时支持按类型和任意移除,适配不同业务场景需求。
内容的提问来源于stack exchange,提问作者Moish
相关产品推荐
相关产品推荐

