简体   繁体   English

C ++ OO设计:模板参数的继承

[英]C++ OO design: Inheritance of template parameter

I have an inheritance chain with Base being the base class. 我有一个继承链,其中Base是基类。 I want to be able to write a class template which inherits Base and possible another Base-derived class. 我希望能够编写一个继承了Base并可能继承另一个Base派生类的类模板。 I could use virtual inheritance, but I found another solution. 我可以使用虚拟继承,但是找到了另一个解决方案。 I'd like to know if it's common/considerable/legitimate class design: 我想知道它是否是通用/合理/合法的类设计:

Write a class template in which the template parameter is the class it derives from, ie it has to be Base or a Base-derived class. 编写一个类模板,其中template参数是它派生自的类,即它必须是Base或Base派生的类。 In the constructor I can use static assert to really make sure the user didn't use any illegal class as the template parameter. 在构造函数中,我可以使用静态断言来确保用户没有使用任何非法类作为模板参数。

If it works, I won't ever have virtual inheritance problems... the question is, it it ok to do that. 如果可行,我将永远不会遇到虚拟继承问题……问题是,这样做是可以的。 I never saw it in other projects, so I want to make sure before I use it. 我在其他项目中从未见过它,因此我想确定在使用它之前。

EDIT : Just to be sure I don't confuse you, here's some code: 编辑 :为了确保我不会混淆您,这是一些代码:

class Base
{
};

class Derived : public Base
{
};

template <Class TheBase>
class MyDerived : public TheBase
{
};

Now I can use Base or any Base -derived class, eg Derived , as the TheBase parameter. 现在,我可以将Base或任何Base派生的类(例如Derived )用作TheBase参数。

This is a valid design pattern. 这是有效的设计模式。 It is mixin inheritance, not CRTP. 它是mixin继承,而不是CRTP。 Mixin inheritance provides a way to simulate multiple inheritance safely by the programmer manually linearizing the inheritance hierarchy. Mixin继承通过程序员手动线性化继承层次结构,提供了一种安全地模拟多重继承的方法。 The templated classes are the mixins. 模板化的类是mixins。 If you want to extend a class with multiple mixins you have to decide the order of the composition like Big<Friendly<Dog> > . 如果要使用多个mixin扩展类,则必须确定合成的顺序,例如Big<Friendly<Dog> > Mixin programming in C++ is described in this Dr Dobb's article . Dobb博士的文章中介绍了C ++中的Mixin编程。 Mixins can be used to implement a static version the GoF Decorator pattern as described here . 混入可以被用来实现静态版本GoF的Decorator模式的描述在这里 Mixins play a simlar role in C++ that traits (not C++ traits) play in Scala & SmallTalk. Mixins在C ++中扮演类似的角色,特征(不是C ++特征)在Scala和SmallTalk中扮演。

In CRTP it is the base class that is a template: CRTP中,基类是模板:

template <class Param>
class Base { ... };

class Derived : public Base<Derived> { ... };

Later edit: One year later, here I am revising my own answer. 以后编辑:一年后,我在这里修改自己的答案。 I initially erroneously stated that the pattern OP posted was CRTP. 我最初错误地指出发布的模式OP是CRTP。 This is not correct. 这是不正确的。 It is indeed a mixin, please read Daniel Mahler's answer lower on the page for the correct explanation. 确实是一个问题,请阅读本页下方Daniel Mahler的答案以获取正确的解释。

Original: It is ok to use such a design. 原文:可以使用这样的设计。 WTL uses it for example. WTL例如使用它。 It is used to implement Static Polymorphism and is called Curiously recurring template pattern 它用于实现静态多态性 ,称为好奇重复模板模式

This is fine, as Zadirion points out. 正如Zadirion所指出的,这很好。 The reason it works (simplified) is that templates in C++, unlike generics in C#, are compile-time. 它起作用(简化)的原因是,与C#中的泛型不同,C ++中的模板是编译时的。 It would be remiss of me to say "it's a typedef" and I'd get a lot of flak for it, but let's keep it simple and say it was. 我会说“这是一个typedef”,这让我很失落,对此我会感到很惊讶,但是让我们保持简单并说出来。

Consider: 考虑:

class base {
protected:
    base() { };
    virtual ~base() { };
};

template<class T>
class super : public T {
};

and later: 然后:

super<base> s;

Absolutely fine. 绝对好 This is actually a rather beautiful construct. 这实际上是一个相当漂亮的构造。 Because it is compile time, you can choose your base class , which in some design idioms could be very favourable. 因为是编译时间,所以您可以选择基类 ,在某些设计惯用法中,这可能是非常有利的。

Here is a good motto: Use templating for the types, but inheritance for behavior. 这是一个很好的座右铭: 对类型使用模板,对行为使用继承。

Stick to it. 坚持下去。 There are certainly a lot of short cuts / tricks that you might use to get the work done, but in the long run these bad design choices will be headaches. 当然,您可以使用很多捷径/技巧来完成工作,但从长远来看,这些糟糕的设计选择将令人头疼。 If you want to use such, make sure to research the benefits and drawbacks. 如果要使用这种方法,请务必研究其优缺点。

Now, going back to your question, what you asked is possible to do: see CRTP , and Static polymorphism . 现在,回到您的问题,您可以做的是:参见CRTPStatic polymorphism

听起来您在谈论的是“好奇地重复出现的模板模式” ,它是有效的C ++。

What you're trying to do is to inherit from two classes which may have a common base class, is that correct? 您想做的是从两个可能具有共同基类的类继承,是正确的吗? In that case you shoul deal with virtual inheritance problems (ie you'll have to declare as virtual the inheritance of the base class for both the two classes you're interested in). 在那种情况下,您应该处理虚拟继承问题(即,您必须将您感兴趣的两个类的基类的继承声明为虚拟 )。 That would just cause a small (likely insignificant) overhead due to some runtime support (2 vpointers more). 由于某些运行时支持(仅2个vpointer),这只会导致很小的开销(可能微不足道)。

Your code isn't the CRTP (in CRTP the base class is the one templated receiving the derived class) and doesn't seem to address in any way the double inheritance problem you was trying to get rid of. 您的代码不是CRTP(在CRTP中,基类是接收派生类的模板化模板),并且似乎没有以任何方式解决您试图摆脱的双重继承问题。

As far as I can see it you can either accept virtual inheritance and use the virtual keyword incurring in a minimal overhead or you can refactor your code. 据我所知,您可以接受虚拟继承并使用虚拟关键字以最小的开销发生,也可以重构代码。

I didn't completely understand what you're trying to do but if you're trying to inherit from two different classes with a common base class (virtual inheritance is all about this) and for some reason you don't want to use the virtual keyword, then you might use the CRTP in the following fashion: 我不完全了解您要执行的操作,但是如果您尝试从具有相同基类的两个不同的类继承(虚拟继承就是这个问题),并且由于某些原因,您不想使用虚拟关键字,那么您可以按以下方式使用CRTP:

#include <iostream>
using namespace std;

template<class Derived>
class Base
{
public:
    void basefunc() { cout << "base here"<< endl; }
    virtual void polyfunc() { cout << "base poly here"<< endl; }
};

class Derived : public Base<Derived>
{
public:
    void derivedfunc() { cout << "derived here"<< endl; }
    virtual void polyfunc() { cout << "derived poly here"<< endl; }
};

class OtherDerived : public Base<OtherDerived>
{
public:
    void otherderivedfunc() { cout << "otherderived here"<< endl; }
    virtual void polyfunc() { cout << "otherderived poly here"<< endl; }
};

class InheritingFromBoth : public Derived, public OtherDerived
{
public:
    void inheritingfunc() { cout << "inheritingfromboth here" << endl; }
    virtual void polyfunc() { cout << "inheritingfromboth poly here"<< endl; }  
};

int main() {

    Derived obj;
    OtherDerived obj2;

    InheritingFromBoth *obj3 = new InheritingFromBoth();
    Derived *der = dynamic_cast<Derived*>(obj3);
    der->polyfunc();
    OtherDerived *der2 = dynamic_cast<OtherDerived*>(obj3);
    der2->polyfunc();

    Base<Derived>* bptr = dynamic_cast<Base<Derived>*>(obj3);
    bptr->polyfunc();
    Base<OtherDerived>* bptr2 = dynamic_cast<Base<OtherDerived>*>(obj3);
    bptr2->polyfunc();



    return 0;
}

by creating two different instances of the base class you'll avoid inheritance ambiguities. 通过创建基类的两个不同实例,您将避免继承歧义。

A simpler, perhaps cleaner, better solution if you intend to inherit from a base and a base-derived class at the same time is the following: 如果您打算同时从基类和基类继承,则一个更简单,也许更干净的更好的解决方案如下:

  • Inheriting from a class Base and from a Base-derived class makes me think that you want to be able to access Base methods and Base-derived methods at the same time.. 从类Base 继承自Base的类继承使我认为您希望能够同时访问Base方法和Base派生的方法。

if you pay attention in your class designing to potential name-hiding problems and just use polymorphism to "customize" the behavior of functions you actually want to be different (and that can be cast-controlled), then a clean hierarchy as Base -> Derived -> YourClass could eventually solve your problems. 如果您在课堂设计中注意潜在的名称隐藏 问题,而只是使用多态性“自定义”您实际上想要有所不同(并且可以强制转换控制)的功能的行为,则可以使用Base -> Derived -> YourClass层次结构Base -> Derived -> YourClass最终可以解决您的问题。

In your specific case your approach works, as noted by others as been used throughout many applications but I don't think can effectively solve your double inheritance issue. 在您的特定情况下,您的方法可以奏效,正如其他人指出的那样,在许多应用程序中都使用过这种方法,但是我认为无法有效解决您的双重继承问题。 Eventually only the specific design case can lead to the lesser-evil solution. 最终,只有特定的设计案例才能导致邪恶的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM