满足纯模拟类继承的虚函数契约

时间:2018-03-13 20:58:05

标签: c++ templates pure-virtual

如果之前已经回答过道歉;我搜索了Stack Overflow,但却找不到类似的东西。我有一种感觉,我所要求的是不可能的,但我确信必须有办法实现它。

我正在使用一个基类,该基类包含许多集成到逻辑相关组中的纯虚函数。我不是简单地在派生类中实现这些,而是​​理想地将函数分组到处理相关功能的类中,然后将它们拉到我的派生类中。

我尝试使用(下面的简化示例),但收到以下错误:

// The base class - I can't change this
class Base {
    public:
    virtual void toImplement(double a) = 0;
};

// Implements logically grouped functionality required by the base class
class Implementor {
    public:
    virtual void toImplement(double a) {}
};

// Concrete derived class, satisfying Base functional requirements by
// (somehow) drawing on the Implementor class functionality.
template <typename Type>
class Derived : public Base, Type {
};

int main() {
    Derived<Implementor> a; // Fails
}

失败并显示错误:

error: variable type 'Derived<Implementor>' is an abstract class
    Derived<Implementor> a;
                         ^
note: unimplemented pure virtual method 'toImplement' in 'Derived'
    virtual void toImplement(double a) = 0;

任何人都可以提出一种方法,我可以实现这个或类似的东西吗?主要的限制是我不能改变基类。

2 个答案:

答案 0 :(得分:1)

如果你必须处理可怕的钻石继承,你可以这样做:

class Base {
    public:
    virtual void toImplement(double a) = 0;
};

class Implementor : public virtual Base {
    public:
    virtual void toImplement(double a) {}
};

template <typename Type>
class Derived : public virtual Base, virtual Type {
};

int main() {
    Derived<Implementor> a; // Fails
}

现在的方式,toImplement中的ImplementorBase中意外名称相似的功能无关。

答案 1 :(得分:1)

如果我正确理解了这个问题,你想使用其他类来注入实现的方法。

您只需要将函数调用委托给实现者。以下代码更通用,因为它可以将许多实现者组合在一起。

注意:由于折叠表达式,它在C ++ 17中。但是您可以使用前C ++ 17方式轻松实现此功能。

#include <tuple>
#include <iostream>
#include <memory>

struct Base {
    virtual void toImplement(double a) = 0;
};

template <class... Impls>
struct Derived : public Base {
    virtual void toImplement(double a) override {
        do_all(a, std::index_sequence_for<Impls...>{});
    }
    std::tuple<Impls...> impls;
private:
    template<std::size_t... Is>
    void do_all(double a, std::index_sequence<Is...>) {
        (std::get<Is>(impls).do_(a), ...);
    }
};

// test
struct Implementor1 {
    void do_(double a) { std::cout << "first impl do: " << a << "\n"; }
};

struct Implementor2 {
    void do_(double a) { std::cout << "second impl do: " << a << "\n"; }
};

int main() {
    std::unique_ptr<Base> ptr = std::make_unique<Derived<Implementor1, Implementor2>>();

    ptr->toImplement(2.3);
}