Наследование от класса шаблона в c ++

106

Допустим, у нас есть шаблонный класс Area, который имеет переменную-член T area, а T getArea()и void setArea(T)функции-члены.

Я могу создать Areaобъект определенного типа, набрав Area<int>.

Теперь у меня есть класс Rectangle, наследующий этот Areaкласс. Поскольку Rectangleсам по себе не является шаблоном, я не могу печатать Rectangle<int>.

Как мне специализировать унаследованный Areaтип для Rectangleобъектов?

РЕДАКТИРОВАТЬ: Извините, я забыл уточнить - мои вопросы заключаются в том, можно ли наследовать Area без ее специализации, поэтому она не наследуется как Area of ​​int, а как Area Rectangle может специализировать типы для.

dtech
источник
4
Это шаблон класса , потому что это шаблон, из которого создаются классы.
sbi
1
@sbi Я не собираюсь начинать здесь пламенную войну, но если Бьярн Страуструп не проводит различия между шаблоном класса и классом шаблона (см. Язык программирования C ++ , 4-е изд., раздел 23.2.1), то вам не следует этого делать. тоже нет.
Майкл Уорнер
@MichaelWarner Я, кажется, помню, как он делал различие. Однако это было в 90-х годах в Usenet. Может, с тех пор он сдался. (Или, может быть, он ссылается на
созданный

Ответы:

245

Для понимания шаблонов огромным преимуществом является четкое понимание терминологии, потому что то, как вы о них говорите, определяет способ о них думать.

В частности, 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и той же функции (которая сама не должна знать тип области). Поскольку 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
};
Celtschk
источник
Примечание. Параметр типа шаблона является частью класса объекта, который создает экземпляр этого шаблона класса. Другими словами, это не компонент класса, это часть типа.
Никос
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>
{

};
pezcode
источник
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 02
6
Во-первых, это действительно старый вопрос, на который уже есть отличный ответ. Во-вторых, избегайте ответов (и вопросов), которые являются всего лишь кодом. Также полезно включить подробные объяснения.
Marcman 08