Успадкування від шаблонного класу в c ++


106

Скажімо, у нас є клас шаблонів Area, який має змінну member T area, a T getArea()та void setArea(T)member.

Я можу створити Areaоб’єкт певного типу, ввівши Area<int>.

Зараз у мене є клас, Rectangleякий успадковує Areaклас. Оскільки Rectangleсам по собі не є шаблоном, я не можу вводити текст Rectangle<int>.

Як я спеціалізую успадкований Areaтип для Rectangleоб'єктів?

EDIT: Вибачте, я забув уточнити - мої запитання полягають у тому, чи можна успадковувати Area без спеціалізації, тому вона не успадковується як Area of ​​ints, а як Area Rectangle може спеціалізуватися на типах.


3
Це шаблон класу , тому що це шаблон, з якого генеруються класи.
sbi

1
@sbi Я не маю наміру розпочати тут полум’яну війну, але якщо Bjarne Stroustrup не розрізняє шаблон класу та клас шаблонів (див . Мова програмування C ++ , 4-е видання, розділ 23.2.1), тоді ви не повинні ні.
Майкл Уорнер

@MichaelWarner Я, здається, пам'ятаю, як він робив це. Однак це було у 90-х на Usenet. Можливо, відтоді він здався. (Чи, можливо, він посилається на шаблони класу з оригінальним класом як клас шаблонів?)
sbi

Відповіді:


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функції одній і тій же функції (що самому не потрібно знати тип області). Оскільки 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
};

Примітка: Параметр типу шаблону є частиною класу об'єкта, який створює шаблон цього шаблону. Іншими словами, це не складова класу, це частина типу.
Нікос

21

Ви просто намагаєтесь вийти Area<int>? У такому випадку ви робите це:

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

EDIT: Після уточнення, здається, ви насправді також намагаєтеся зробити Rectangleшаблон, і в такому випадку слід працювати наступне:

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


8

Зробіть прямокутник шаблоном та передайте ім'я типу в область:

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();
}

що робити, якщо у вас були методи у похідному класі? Як би ви їх визначили? І більшість імпортує поки що, принаймні для мене, як ви називаєте / використовуєте ці методи у вашій головній () функції?
Картопля

6
По-перше, це справді старе питання, на яке вже є чудова відповідь. По-друге, будь ласка, уникайте відповідей (і питань), які є лише кодом. Корисно також включити детальні пояснення.
marcman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.