首页 > 解决方案 > 为虚拟方法实现组合行为

问题描述

假设我有几个类的层次结构:

class A {
public:
    virtual void DoStuff() = 0;
};

class B : public A {
public:
    // Does some work
    void DoStuff() override;
};

class C : public B {
public:
   // Calls B::DoStuff and does other work
   void DoStuff() override;
};

它可以天真地实现:

void Derived::DoStuff() {
    Base::DoStuff();
    ...
}

我相信这个实现有一个严重的问题:人们总是必须记住在覆盖时调用基本实现。

选择:

class A {
public:
    void DoStuff() {
        for (auto& func: callbacks_) {
            func(this);
        }
    }

    virtual ~A() = default;
protected:
    template <class T>
    void AddDoStuff(T&& func) {
        callbacks_.emplace_back(std::forward<T>(func));
    }

private:
    template <class... Args>
    using CallbackHolder = std::vector<std::function<void(Args...)>>;

    CallbackHolder<A*> callbacks_;
};

用法:

class Derived : public Base {
public:
    Derived() {
        AddDoStuff([](A* this_ptr){
            static_cast<Derived*>(this_ptr)->DoStuffImpl();
        });
    }
private:
    void DoStuffImpl();
};

DoStuff()但是,与第一个实现相比,我相信在实际调用时它会产生大量开销。在我看到的用例中,对象的长构造可能不是问题(如果他愿意,也可以尝试实现诸如“短向量优化”之类的东西)。

另外,我认为每种DoStuff方法的 3 个定义有点过多的样板文件。

我知道通过使用类似于 CRTP 的继承模式可以非常有效地解决它,并且可以将基于模板的解决方案隐藏在接口类后面(A在示例中),但我一直想知道——难道不应该有更简单的解决方案吗?

call DERIVED implementation FROM BASE, if and only if derived class exists and it has an overriding method对长继承链(或等效的东西)的良好实现感兴趣。

谢谢!

编辑:我知道@Jarod42 的回答中描述的一个想法,我认为它不合适,因为我认为它对于长继承链来说是丑陋的——必须为每个层次结构使用不同的方法名称。

标签: c++compositionvirtual-functionsvirtual-inheritance

解决方案


您可以将您的课程更改B为:

class A {
public:
    virtual ~A() = default;
    virtual void DoStuff() = 0;
};

class B : public A {
public:
    void DoStuff() final { /*..*/ DoExtraStuff();  }

    virtual void DoExtraStuff() {}
};

class C : public B {
public:
   void DoExtraStuff() override;
};

推荐阅读