如何围绕模板化成员函数不能虚拟的限制进行设计

时间:2013-03-23 21:43:10

标签: c++ templates virtual

我遇到了一个设计问题,其中(在C ++中)我喜欢模板化的成员函数(非模板类)是虚拟的,我想知道是否有一个好的,优雅的方式围绕这个问题。

方案是,我有机器 进程通用。我使用带有虚拟进程(Item)函数的 machines 的抽象基类,以便每台机器都可以定义自己独特的处理方法。问题是这些物品也是"泛型"因为它们暴露了某些接口以便如何处理它们。由于原因(主要是为了性能......没有vtable开销),我想对这些项使用编译时多态。所以现在每台机器都有一个如下界面:

class Machine
{ public:
    template <typename T>
    virtual void process(T& item) = 0; 
};

然而,在C ++中这是不可能的,因为模板化的成员函数不能是虚拟的。当然,我可以在Item类型T上模拟机器类,但这会在更大的设计方案中为我增加更多的麻烦,而且Machine类的其他任何部分都不依赖于Item ...它只是一个参数process()函数。

是否有更好的方法来解决这个或如何提供这种通用系列机器来处理一系列通用项目(其中项目使用编译时多态)的方法。在我的设计方面,我是否已经走到了尽头。

感谢任何建议

1 个答案:

答案 0 :(得分:3)

通常使用双重调度。

class Machine;
class Item {
public:
    virtual void bounce(Machine& mach);
};
class Machine {
public:
    template<typename T> void process(T& t);
    virtual void process(Item& i) {
        return i.bounce(*this);
    }
};
template<typename T> class CRTPItem {
public:
    virtual void bounce(Machine& mach) {
        return mach.process(*(T*)this);
    }
};
class ConcreteItem : public CRTPItem<ConcreteItem> {
public:
    // blah blah
};

在这种情况下,您不需要整个ConcreteItem接口的虚拟开销,并且它们不需要任何共同点,只需要通过继承自{{{}}自动构建的bounce函数。 1}}。这只是两个vtable调用而不是你原来的调用,而不是需要对所有Item函数进行vtable调用,并且接口仍然可以保留所有强类型,如果你可以创建虚拟模板。< / p>