如何借助CRTP实现Base指针的Derived类型擦除以构建异构容器
解决方案
你可以通过引入非模板的公共抽象基类消除模板参数依赖,把需要多态调用的接口定义为纯虚函数,再让原来的CRTP模板类继承这个公共基类即可。
具体实现逻辑
- 定义无模板参数的抽象基类
IBase,声明需要多态调用的接口f()为纯虚函数,同时定义虚析构函数避免内存泄漏 - 让原CRTP模板类
Base<T>继承IBase,重写f()接口实现CRTP的静态分发 - 容器直接存储
IBase*类型的指针即可,遍历调用时直接走普通的虚函数多态逻辑
完整可运行代码
#include <iostream> #include <vector> // 非模板公共抽象基类 class IBase { public: virtual void f() = 0; virtual ~IBase() = default; }; template<typename T> class Base : public IBase { public: // 重写虚接口,内部走CRTP静态分发 void f() override { static_cast<T*>(this)->f(); } }; class Derived1 : public Base<Derived1> { public: void f() { std::cout << "Derived1::f()\n"; } }; class Derived2 : public Base<Derived2> { public: void f() { std::cout << "Derived2::f()\n"; } }; int main() { std::vector<IBase*> vec; vec.push_back(new Derived1); vec.push_back(new Derived2); // 遍历容器直接调用接口,无需关心具体派生类类型 for (auto ptr : vec) { ptr->f(); } // 释放资源 for (auto ptr : vec) { delete ptr; } vec.clear(); return 0; }
可选替代方案
如果你不想引入虚函数(比如要避免虚函数的运行时开销),也可以用类型擦除技术(自行封装包含调用入口的擦除层,或者直接使用std::function包装可调用对象)实现相同的效果,不过实现复杂度比继承公共基类的方案更高。
内容的提问来源于stack exchange,提问作者Eduard Rostomyan
相关产品推荐
相关产品推荐

