C++如何编写接收模板接口具体实现类的方法?
问题分析与解决
错误原因
ISource<Bread>和ISource<IProduct>是模板类ISource<T>的不同实例,二者无继承关系——即便Bread继承自IProduct,模板实例化后的类也不会自动产生协变,因此编译器拒绝这种隐式类型转换。
可行解决方案
方案1:为ISource添加非模板基类
通过引入非模板基类统一接口,让IProducer接收基类指针,同时保留具体ISource<T>的类型特性:
// 新增非模板基类,定义统一接口 class ISourceBase { public: virtual ~ISourceBase() = default; virtual IProduct* getProduct() = 0; }; // 修改ISource模板,继承自ISourceBase并实现统一接口 template<typename T> class ISource : public ISourceBase { public: virtual T* get() = 0; IProduct* getProduct() override { return get(); } }; // 调整IProducer的produce参数类型 class IProducer { public: virtual IProduct* produce(ISourceBase* source) = 0; }; class Shop : public IProducer { public: IProduct* produce(ISourceBase* source) override { return source->getProduct(); } }; // 原test函数可直接使用 template<typename T> T* test(IProducer* producer, ISource<T>* source) { return dynamic_cast<T*>(producer->produce(source)); } int main(int argc, char** argv) { auto bakery = new Bakery(); auto shop = new Shop(); Bread* bread1 = test(shop, bakery); // 清理内存 delete bread1; delete bakery; delete shop; return 0; }
方案2:将IProducer改为模板类
如果不需要IProducer作为多态基类,直接将其模板化,让produce接收对应类型的ISource<T>:
// 模板化IProducer template<typename T> class IProducer { public: virtual T* produce(ISource<T>* source) = 0; }; // 针对具体产品实现Shop template<typename T> class TypedShop : public IProducer<T> { public: T* produce(ISource<T>* source) override { return source->get(); } }; // test函数无需动态转换 template<typename T> T* test(IProducer<T>* producer, ISource<T>* source) { return producer->produce(source); } int main(int argc, char** argv) { auto bakery = new Bakery(); auto shop = new TypedShop<Bread>(); Bread* bread1 = test(shop, bakery); delete bread1; delete bakery; delete shop; return 0; }
方案3:使用适配器包装具体ISource
通过适配器类将ISource<T>转换为ISource<IProduct>,适配现有IProducer接口:
// 适配器类,将ISource<T>包装为ISource<IProduct> template<typename T> class SourceAdapter : public ISource<IProduct> { private: ISource<T>* m_source; public: explicit SourceAdapter(ISource<T>* source) : m_source(source) {} IProduct* get() override { return m_source->get(); } }; // 修改test函数,使用适配器转换类型 template<typename T> T* test(IProducer* producer, ISource<T>* source) { SourceAdapter<T> adapter(source); return dynamic_cast<T*>(producer->produce(&adapter)); } // 主函数无需修改,可正常编译运行 int main(int argc, char** argv) { auto bakery = new Bakery(); auto shop = new Shop(); Bread* bread1 = test(shop, bakery); delete bread1; delete bakery; delete shop; return 0; }
方案选择建议
- 若需保留
IProducer的多态能力,优先选方案1(扩展性更好)或方案3(无需修改原有接口结构); - 若仅针对具体类型处理,不需要多态,方案2实现最简单。
内容的提问来源于stack exchange,提问作者Jan Šimek
相关产品推荐
相关产品推荐

