如何用接收std::vector<Animal*>的函数清理派生类vector以避免代码重复
搞定通用动物列表清理:避免重复代码的两种方案
嘿,这个场景太常见了——不想写两遍几乎一样的清理逻辑?完全没问题,我们可以用C++的模板或者多态特性来搞定,下面给你两种靠谱的方案:
方案一:用模板函数实现通用清理
既然Cat和Dog都是Animal的派生类,我们可以写一个模板函数,让它能处理任意存储Animal子类指针的vector,一套逻辑走天下:
class House { private: std::vector<Cat*> cats; std::vector<Dog*> dogs; // 私有模板辅助函数,负责清理任意Animal子类的vector template<typename AnimalSubclass> void clearAnimalList(std::vector<AnimalSubclass*>& animalList) { // 逐个释放对象内存 for (auto* animal : animalList) { delete animal; } // 清空vector animalList.clear(); } public: // 一次性清理所有动物 void clearAllAnimals() { clearAnimalList(cats); clearAnimalList(dogs); } // 也可以单独清理某一类 void clearCats() { clearAnimalList(cats); } void clearDogs() { clearAnimalList(dogs); } };
这个方案的优点很明显:
- 彻底消除重复代码,新增任何
Animal子类(比如Bird),直接调用clearAnimalList(birds)就行 - 类型安全,模板会自动推导子类类型,不会有类型错误
- 逻辑清晰,把通用的清理逻辑封装在模板里,对外只需要调用简单的接口
方案二:适配你想要的clearList(std::vector<Animal*>)签名
如果你坚持要用这个函数签名,这里要注意:vector<Cat*>不能直接转成vector<Animal*>(容器类型不匹配),但我们可以用模板重载来适配:
class House { private: std::vector<Cat*> cats; std::vector<Dog*> dogs; // 基类指针版本的清理函数 void clearList(std::vector<Animal*>& animalList) { for (auto* animal : animalList) { delete animal; } animalList.clear(); } // 模板重载,处理子类指针的vector template<typename T> void clearList(std::vector<T*>& animalList) { // 子类指针可以安全转成基类指针,然后调用基类版本的逻辑 for (auto* animal : animalList) { delete static_cast<Animal*>(animal); } animalList.clear(); } public: void clearAllAnimals() { clearList(cats); clearList(dogs); } };
不过说实话,这个方案和模板方案本质差不多,只是更贴合你最初设想的函数名而已。
关键注意事项!
一定要给Animal类加虚析构函数!不然通过Animal*指针删除子类对象时,只会调用基类的析构函数,子类的资源没法正确释放,会导致内存泄漏:
class Animal { public: virtual ~Animal() = default; // 必须是虚析构! // 其他成员... };
另外,如果以后改用智能指针(比如std::unique_ptr<Cat>),就不用手动delete了,直接调用animalList.clear()就行,模板函数依然适用,只需要删掉delete那行代码~
内容的提问来源于stack exchange,提问作者Gabel Luc
相关产品推荐
相关产品推荐

