是继承模板参数不好的做法吗?

时间:2014-07-29 21:52:18

标签: c++ templates inheritance

因此,在最近的C ++项目中,我开始发现一种快速解耦大量代码的方法是编写从模板参数继承的模板类。这是一个一般的例子:

class BaseBehavior
{
    // this class has a well defined and extensive interface, however I'll show this function as an example
    virtual const std::string name() const {return "base1";};
};

class DerivedBehavior: public BaseBehavior
{
     // may add functions to the interface or override any virtual in BaseBehavior
     virtual const std::string name() const {return "base2";};
};

这是两种不同的行为,然后由至少两个其他类继承

template<class T>
class ImplementBehavior1: public T
{
    // an important feature is that this inherits the interface of T as well
    virtual const std::string greet() const {return "hello"+name();};
};

template<class T>
class ImplementBehavior2: public ImplementBehavior1<T>
{
     // now this can has T's interface as well as ImplementedBehavior's
     virtual const std::string greet() const {return "good evening"+name();};
};

我在我的代码中使用了这种技术(在一个更有用的情况下),基本上我几乎想要一个行为表。这里我们可以有4个不同的类,有4种不同的行为。我首先注意到这个策略可以在没有模板的情况下使用多态组件获得相同的好处,但是我的代码并不要求实现在运行时是动态的,并且这也解耦了很多代码,因为我能够继承接口,而不必担心编写存根接口。此外,它允许在编译时发生很多事情,我想这会使它在运行时更高效。 我从来没有见过这种风格的建议而且它看起来很模糊,但是我发现它是我案例的最佳方式,我可以看到自己在很多情况下应用它。我想知道这个结构是否有任何固有的缺陷,我现在不知道了?

2 个答案:

答案 0 :(得分:2)

我想这取决于你的概念的实际用法,如果它是最好的方式,但是使用模板类在编译时执行通用任务是一种非常常见的方式。

Atm我在工作中使用图书馆处理医学图像,这些图像完全基于模板并且工作得非常好,所以不要介意你的概念并继续前进!

干杯使用

PS:这是基于模板的lib:http://www.itk.org/ITK/help/documentation.html

答案 1 :(得分:2)

正如您所询问的那样

  

&#34;是继承模板参数的不良做法吗?&#34;

我说它(经常)完全取决于你的实际用例。可能有效用途,但更常见的是:

  • 模板类应该是T的包装器,然后在大多数情况下,T member; 1 变量将是最合适的选择。
  • 模板类应提供一些混合行为 2 ,然后经典CRTP,其中T继承混合实现将是更好的选择。
  • 在第1点中提到的情况很少见 3 ,只需使用包装类派生T就可以节省工作量,但这可能会引入更多问题(例如,冲突继承结构)。

(1)

template<typename T>  
class Wrapper {
public:
    void foo() { member.foo(); }
protected:
    T member;
};

(2)

template<class Derived>
class MixIn {
public:
    void foo() { static_cast<Derived*>(this)->doFoo(); }
protected:
    MixIn() {}
    void doFoo() {
        // Provide a default implementation
    }
};

class Impl : public MixIn<Impl> {
    friend class MixIn<Impl>;

    // Optionally provide a deviate implementation
    // void doFoo() {
    //     // Optionally include the default behavior
    //     MixIn<Impl>::doFoo()
    // }    
};

(3)

template<class Base>
class Adapter : public Base {
public:
    Adapter() : Base() {}
    Adapter(const Adapter& rhs) : Base(rhs) {}
    Adapter& operator=(const Adapter& rhs) {
        Base::operator=(rhs);
        return *this;
    }

    // Totally depends on what needs to be adapted
};

别担心:
简单继承几乎总是错误的选择。该主题与特定或主要的模板和元编程无关。