Для розуміння шаблонів величезна перевага розібратися в термінології, оскільки те, як ви говорите про них, визначає спосіб їх думати.
Зокрема, 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
};