菱形多重继承场景下,如何让Apple与Fruit各自独立实现Fooable的fooify?
问题描述
我定义了一个用于实现fooization机制的抽象基类Fooable,所有需要该机制的对象都继承它:
#include <unordered_set> class Fooable { public: Fooable() { registered.insert(this); } ~Fooable() { registered.erase(this); } virtual void fooify() = 0; static void fooify_all() { for(auto * f : registered) f->fooify(); } private: static std::unordered_set<Fooable*> registered; }; std::unordered_set<Fooable*> Fooable::registered;
接着定义了私有继承Fooable的基类Fruit,并给出fooify的私有实现(标记为final):
class Fruit : private Fooable { void fooify() override final { /* 访问Fruit私有成员 */ } };
然后是派生类Apple,同样私有继承Fooable,想要实现自己独立的fooify:
class Apple : public Fruit, private Fooable { void fooify() override final { /* 访问Apple私有成员 */ } };
我的核心需求是:
Apple和Fruit各自拥有独立的fooify私有实现,用于访问自身私有成员- 两者的
fooify能被独立调用
但编译器报错,认为Apple试图重写被标记为final的Fruit::fooify,但实际上这两个fooify属于不同的Fooable实例,本应互不相关。如果添加间接层会导致大量访问器或友元类的使用,现寻求可行的实现或重构方案。
解决方案
方案1:用成员对象替代私有继承
将Fooable作为类的私有成员而非基类,彻底避免多重继承带来的虚函数冲突。通过包装类适配目标类的调用:
#include <unordered_set> class IFooable { public: virtual void fooify() = 0; virtual ~IFooable() = default; static void fooify_all() { for(auto * f : registered) f->fooify(); } protected: static std::unordered_set<IFooable*> registered; }; std::unordered_set<IFooable*> IFooable::registered; // 模板包装类,转发fooify调用到目标类 template<typename T> class FooWrapper : public IFooable { public: explicit FooWrapper(T* obj) : m_obj(obj) { registered.insert(this); } ~FooWrapper() { registered.erase(this); } void fooify() override { m_obj->do_fooify(); } private: T* m_obj; }; class Fruit { public: Fruit() : m_foo_wrapper(this) {} private: void do_fooify() { /* 访问Fruit私有成员 */ } FooWrapper<Fruit> m_foo_wrapper; }; class Apple : public Fruit { public: Apple() : m_foo_wrapper(this) {} private: void do_fooify() { /* 访问Apple私有成员 */ } FooWrapper<Apple> m_foo_wrapper; };
Fruit和Apple各自持有独立的FooWrapper实例,它们的fooify调用完全隔离,不会产生继承层面的冲突。
方案2:CRTP实现独立基类实例
通过奇异递归模板模式(CRTP)创建不同的Fooable派生类,让Fruit和Apple继承完全独立的基类:
#include <unordered_set> // 统一接口类 class IFooable { public: virtual void fooify() = 0; virtual ~IFooable() = default; static void fooify_all() { for(auto * f : registered) f->fooify(); } protected: static std::unordered_set<IFooable*> registered; }; std::unordered_set<IFooable*> IFooable::registered; // CRTP模板,每个实例都是独立的基类 template<typename Derived> class Fooable : public IFooable { public: Fooable() { registered.insert(this); } ~Fooable() { registered.erase(this); } void fooify() override { static_cast<Derived*>(this)->do_fooify(); } }; class Fruit : private Fooable<Fruit> { friend class Fooable<Fruit>; private: void do_fooify() { /* 访问Fruit私有成员 */ } }; class Apple : public Fruit, private Fooable<Apple> { friend class Fooable<Apple>; private: void do_fooify() { /* 访问Apple私有成员 */ } };
Fooable<Fruit>和Fooable<Apple>是两个完全不同的类,因此Fruit和Apple的fooify实现互不干扰,也不会触发final的冲突报错。
方案3:调整注册逻辑,避免多重继承
如果Fruit不需要单独的fooify能力,可改为手动注册Fooable实例,而非在构造函数自动注册:
#include <unordered_set> class Fooable { public: virtual void fooify() = 0; virtual ~Fooable() = default; static void fooify_all() { for(auto * f : registered) f->fooify(); } static void register_fooable(Fooable* obj) { registered.insert(obj); } static void unregister_fooable(Fooable* obj) { registered.erase(obj); } private: static std::unordered_set<Fooable*> registered; }; std::unordered_set<Fooable*> Fooable::registered; class Fruit { // Fruit的私有成员 }; class Apple : public Fruit, private Fooable { public: Apple() { Fooable::register_fooable(this); } ~Apple() { Fooable::unregister_fooable(this); } private: void fooify() override final { /* 访问Apple私有成员 */ } };
此方案仅适用于无需Fruit单独实现fooify的场景,若Fruit也需要独立能力,优先选择前两个方案。
内容的提问来源于stack exchange,提问作者galinette
相关产品推荐
相关产品推荐

