利用C++模板与Concept实现无继承的类专属func方法
用模板与Concept实现无继承的代码复用(共享proc逻辑+专属func)
问题背景
现有C++代码中,Derived类继承Base类后,调用Derived的proc方法时,执行的是Base类的func,达不到预期的Derived::func输出。需求是:让多个类共享proc里的大量公共代码,同时每个类拥有专属的func方法,完全不使用继承,能否通过模板与Concept编程实现?
原代码
// templateInheritance.cpp #include <iostream> template <typename T> class Base{ public: void func(){ // (1) std::cout << "Base::func\n"; } void proc() { // huge stuff goes here func(); // huge stuff goes here } }; template <typename T> class Derived: public Base<T>{ public: void func(){ // (2) std::cout << "Derived::func\n"; } }; int main(){ std::cout << '\n'; Derived<int> derived; derived.proc(); Base<int> base; base.proc(); std::cout << '\n'; }
预期输出
Derived::func Base::func
解决方案:模板+Concept实现无继承复用
完全可以实现,核心思路是将共享的proc逻辑抽离为模板函数(或模板类),用Concept约束类型必须具备func方法,从而实现编译期的类型检查与代码复用,同时避免继承带来的问题。
方案1:模板自由函数+Concept(推荐)
这种方式最简洁,直接把共享逻辑做成独立的模板函数,只要类满足Concept要求就能调用:
#include <iostream> #include <concepts> // 定义Concept:要求类型必须有可调用的void func()方法 template<typename T> concept HasFunc = requires(T t) { { t.func() } -> std::same_as<void>; }; // 共享的proc逻辑,作为模板函数 template<HasFunc T> void proc(T& obj) { // 这里放置所有公共代码 obj.func(); // 直接调用对象的专属func // 这里放置所有公共代码 } // 自定义Base类,自带专属func class Base { public: void func() { std::cout << "Base::func\n"; } }; // 自定义Derived类,自带专属func class Derived { public: void func() { std::cout << "Derived::func\n"; } }; int main() { std::cout << '\n'; Derived derived; proc(derived); // 调用Derived::func Base base; proc(base); // 调用Base::func std::cout << '\n'; }
方案说明
- Concept
HasFunc在编译期检查传入的类型是否具备void func()方法,不符合的类型会直接触发编译错误,提前发现问题。 proc作为独立模板函数,所有符合要求的类都能直接调用,完全不需要继承关系。- 每个类的
func都是自身的专属实现,proc会直接调用对应对象的func,完美匹配预期输出。
方案2:组合式模板类+Concept
如果需要将共享逻辑封装成类(比如需要持有状态),可以用组合代替继承,把自定义类作为模板类的成员:
#include <iostream> #include <concepts> #include <utility> // 同样用Concept约束类型 template<typename T> concept HasFunc = requires(T t) { { t.func() } -> std::same_as<void>; }; // 封装共享逻辑的模板类,持有自定义类型对象 template<HasFunc T> class ProcHolder { private: T obj_; public: // 转发构造函数,支持自定义类的任意构造方式 template<typename... Args> ProcHolder(Args&&... args) : obj_(std::forward<Args>(args)...) {} void proc() { // 大量公共代码 obj_.func(); // 大量公共代码 } // 暴露底层对象(如果需要调用自定义类的其他方法) T& get_obj() { return obj_; } const T& get_obj() const { return obj_; } }; class Base { public: void func() { std::cout << "Base::func\n"; } }; class Derived { public: void func() { std::cout << "Derived::func\n"; } }; int main() { std::cout << '\n'; ProcHolder<Derived> derived; derived.proc(); ProcHolder<Base> base; base.proc(); std::cout << '\n'; }
方案说明
- 通过组合的方式将自定义类对象嵌入
ProcHolder,避免了继承的耦合。 - 同样依靠Concept确保传入的类型具备
func方法,编译期检查类型合法性。 - 适合需要在共享逻辑中持有状态,或者需要封装更多接口的场景。
为什么原代码失效?
原代码中Base的proc调用的是自身的func,因为func不是虚函数,Derived的func只是隐藏了Base的同名方法,而非多态覆盖。因此调用derived.proc()时,实际执行的是Base<T>::proc,自然会调用Base<T>::func。
内容的提问来源于stack exchange,提问作者Ted Zach
相关产品推荐
相关产品推荐

