将继承转换为模板

时间:2015-09-27 15:59:52

标签: c++ templates c++11 inheritance dry

我有使用继承的C ++ 11项目。这是一个小片段:

class ICountable{
public:
        virtual ~ICountable(){}

        unsigned getCount() const{
                return _getCount();
        }

        bool isEmpty() const{
                return _getCount() == 0;
        }

private:
        virtual unsigned _getCount() const = 0;
};

假设我们有一些LinkList继承自ICountable并实现_getCount()。然后你可以做这样的功能:

void doSomething(ICountable &countable){
    if (countable.isEmpty())
         doSomethingElse();
}
...
LinkList ll;
doSomething(ll);

这一切都非常好,但必须有另一种方法来完成所有这些:

template <typename T>
void doSomething(T countable){
    if (countable.isEmpty())
         doSomethingElse();
}
...
LinkList ll;
doSomething(ll); // we do not even need to add <>

模板方式更快,可能更容易实现。 std::vectorstd::deque也是这样。

但是,我如何避免代码重复 - 函数isEmpty()必须粘贴在所有“列表内容”中。

我可以想象预处理器#include或......

我可以想象decorator - 就像可以实现所有糖方法并代理其他方法的类一样:

template <typename T>
class List{
   T list;
public:
        unsigned getCount() const{
                return list.getCount();
        }

        bool isEmpty() const{
                return list.getCount() == 0;
        }

        ...
}

如果没有运行时多态,什么是更好的继承或模板?

有没有更好的方法来避免代码重复?

2 个答案:

答案 0 :(得分:0)

使用模板,您只需暗示界面。您编写了一个函数模板,并要求您传入的类型符合您的条件。在这种情况下,只需:

template <typename T>
void doSomething(T const& countable) {
    if (countable.empty()) {
         doSomethingElse();
    }
}

所有C ++标准容器都有empty()方法,你可能比复制自己编写的容器的标准接口更糟糕。此函数已经适用于vectorlist以及string和...,所有这些都没有任何动态调度开销或没有必须从某个接口继承的OOP要求。

如果类型具有您需要的接口,则通用编程可以工作 - 它们不需要从所有正确的命名接口继承来获取它们。

答案 1 :(得分:0)

有一个C ++功能尚未正式添加到标准中(但已经在工作了很长一段时间),名为Concepts,基本上允许您声明您的doSomething(T countable)拥有要求T实现某个接口(即它具有isEmpty()功能)。在此之前,如果您想要的是通过在不同类之间共享一组公共函数(re:interface)来避免代码重复,则无法避免多态性。这是首先使用polymorphism的主要原因之一。

话虽如此,你正在寻找评论中提到的Curiously Recurring Template Pattern像Igor Tandetnik。这允许您在类之间共享公共代码,而不会虚拟函数的运行时代价(运行时多态性)。使用CRTP可让编译器为您完成这些工作。

使用简单的基类:

template <typename T>
struct ICountable {
    bool isEmpty() const { return static_cast<T*>(this)->_getCount() == 0; }
};

然后是你的派生名单:

class LinkedList : public ICountable<LinkedList> {
    int _getCount() const { return size; }
};

以这种方式从ICountable派生的任何类现在都有isEmpty()方法,该方法使用特定于实现的_getCount()方法而不使用虚函数。

相关问题