因此,在最近的一个 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 种不同的行为。我首先注意到这种策略在没有模板的情况下也可以有同样的好处,使用多态组件,但是我的代码不要求实现在运行时是动态的,而且这也解耦了很多代码,因为我能够继承接口(interface)而无需不必担心编写 stub 接口(interface)。此外,它让很多事情在编译时发生,我想这会使其在运行时更有效率。 我从来没有见过这种建议的风格,它看起来确实晦涩难懂,但我发现这是适合我的情况的最佳方式,而且我可以看到自己将它应用于很多情况。我想知道这种结构是否存在我现在遗漏的固有缺陷?
最佳答案
如你所问
"Is inheriting a template argument bad practice?"
我会说(一如既往)完全取决于您的实际用例。可能有有效的用途,但更常见的是这些用途:
- 模板类应该是
T
的包装器,那么在大多数情况下T 成员;
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
};
别担心:
普通继承几乎总是错误的选择。该主题与模板和元编程没有特别或主要的关联。
关于c++ - 从模板参数继承是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25025596/