从C ++中的模板类继承


106

假设我们有一个模板类Area,它具有一个成员变量T area,一个T getArea()和一个void setArea(T)成员函数。

我可以Area通过键入创建特定类型的对象Area<int>

现在,我有一个Rectangle继承Area该类的类。由于Rectangle本身不是模板,因此无法键入Rectangle<int>

如何专门化对象的继承Area类型Rectangle

编辑:对不起,我忘了澄清-我的问题是,是否有可能不专门化就继承Area,因此它不是作为int的Area继承的,而是因为Area Rectangle可以将其专门化的类型。


3
这是类模板,因为它是从中生成类的模板。
2012年

1
@sbi我不打算在这里发火,但是如果Bjarne Stroustrup没有在类模板模板类之间进行区分(请参阅C ++编程语言,第四版,第23.2.1节),那么您应该也不是。
Michael Warner

@MichaelWarner我似乎记得他与众不同。那是在90年代,在Usenet上。此后也许他已经放弃了。(或者也许他将实例化的类模板称为模板类?)
sbi

Answers:


244

对于理解模板而言,直接理解术语具有巨大的优势,因为您谈论模板的方式决定了思考模板的方式。

具体来说,Area不是模板类,而是类模板。也就是说,它是可以从中生成类的模板。Area<int>就是这样的一个类(它不是对象,但是您当然可以按照与从任何其他类创建对象相同的方式从该类创建对象)。另一个这样的类是Area<char>。请注意,它们是完全不同的类,除了它们是从同一类模板生成的事实之外,没有其他共同点。

由于Area不是类,因此无法从中派生该类Rectangle。您只能从另一个类(或其中几个)派生一个类。由于Area<int>是一个类,因此您可以从中派生Rectangle

class Rectangle:
  public Area<int>
{
  // ...
};

由于Area<int>Area<char>是不同的类,因此您甚至可以同时从这两个类派生(但是访问它们的成员时,您必须处理歧义):

class Rectangle:
  public Area<int>,
  public Area<char>
{
  // ...
};

但是,您必须在定义时指定要从哪个类别派生Rectangle。不管这些类是否从模板生成,都是如此。同一类的两个对象不能简单地具有不同的继承层次结构。

您可以做的就是制作Rectangle一个模板。如果你写

template<typename T> class Rectangle:
  public Area<T>
{
  // ...
};

您有一个模板Rectangle,可以从中获取一个类Rectangle<int>,该类从派生Area<int>,而另一个类Rectangle<char>从派生Area<char>

可能是您希望有一个单一类型,Rectangle以便可以将各种形式传递Rectangle给同一个函数(它本身不需要知道Area类型)。由于Rectangle<T>实例化模板Rectangle所生成的类在形式上是彼此独立的,因此它不是那样工作的。但是,您可以在此处使用多重继承:

class Rectangle // not inheriting from any Area type
{
  // Area independent interface
};

template<typename T> class SpecificRectangle:
  public Rectangle,
  public Area<T>
{
  // Area dependent stuff
};

void foo(Rectangle&); // A function which works with generic rectangles

int main()
{
  SpecificRectangle<int> intrect;
  foo(intrect);

  SpecificRectangle<char> charrect;
  foo(charrect);
}

如果Rectangle从您的泛型派生泛型很重要,您Area也可以使用相同的技巧Area

class Area
{
  // generic Area interface
};

class Rectangle:
  public virtual Area // virtual because of "diamond inheritance"
{
  // generic rectangle interface
};

template<typename T> class SpecificArea:
  public virtual Area
{
  // specific implementation of Area for type T
};

template<typename T> class SpecificRectangle:
  public Rectangle, // maybe this should be virtual as well, in case the hierarchy is extended later
  public SpecificArea<T> // no virtual inheritance needed here
{
  // specific implementation of Rectangle for type T
};

注意:模板类型参数是实例化该类模板的对象类的一部分。换句话说,它不是类的组成部分,而是类型的一部分。
Nikos '18

21

您只是想从中衍生Area<int>吗?在这种情况下,您可以执行以下操作:

class Rectangle : public Area<int>
{
    // ...
};

编辑:在澄清之后,似乎您实际上也在尝试制作Rectangle模板,在这种情况下,以下方法应该起作用:

template <typename T>
class Rectangle : public Area<T>
{
    // ...
};


8

将Rectangle作为模板,并将类型名称传递给Area:

template <typename T>
class Rectangle : public Area<T>
{

};

6

Rectangle将必须是模板,否则只是一种类型。它的基础不可思议,但它不能是非模板。(它的基础可能是模板实例化,尽管您似乎想将基础的功能保持为模板。)


3
#include<iostream>

using namespace std;

template<class t> 
class base {
protected:
    t a;
public:
    base(t aa){
        a = aa;
        cout<<"base "<<a<<endl;
    }
};

template <class t> 
class derived: public base<t>{
    public:
        derived(t a): base<t>(a) {
        }
        //Here is the method in derived class 
    void sampleMethod() {
        cout<<"In sample Method"<<endl;
    }
};

int main() {
    derived<int> q(1);
    // calling the methods
    q.sampleMethod();
}

如果您在派生类中有方法怎么办?您将如何定义它们?至少对我而言,大多数导入仍然是重要的,至少如何在main()函数中调用/使用这些方法?
Pototo

6
首先,这是一个非常古老的问题,已经有了很好的答案。其次,请避免仅是代码的答案(和问题)。包括详细说明也很有用。
marcman'7
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.