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

Is inheriting from a template argument bad practice?

本文关键字:参数 继承      更新时间:2023-10-16

因此,在最近的一个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种不同的行为。我首先注意到这种策略可以在没有模板的情况下有同样的好处,使用多态组件,但是我的代码不要求实现在运行时是动态的,这也解耦了很多代码,因为我能够继承接口而不必担心编写存根接口。此外,它让很多事情在编译时发生,我想这会使它在运行时更高效。我从来没有见过这种风格的建议,它当然看起来很晦涩,但我发现这是我的情况下最好的方式,我可以看到自己将它应用到很多情况下。我想知道这个结构是否存在我现在遗漏的固有缺陷?

当你问

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

我想说这完全取决于你的实际用例。可能有有效的用法,但更常见的用法是:

  • 模板类应该是T的包装器,那么在大多数情况下,T member; 1变量将是最合适的选择。
  • 模板类应该提供一些混合行为2,然后经典的CRTP,其中T继承了混合实现将是更好的选择。
  • 对于第一点中提到的情况,在极少数情况下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
};

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

我想这取决于你的概念的实际用法,如果它是最好的方式或不是,但使用模板类做泛型任务在编译时是一个相当常见的方式。

我在工作中使用一个库来处理医学图像,这是完全基于模板的,工作得很好,所以不要介意你的概念,继续前进!

欢呼Usche

p。:这是基于模板的库:http://www.itk.org/ITK/help/documentation.html