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