Para entender las plantillas, es una gran ventaja tener la terminología correcta porque la forma en que se habla de ellas determina la forma de pensar en ellas.
Específicamente, Area
no es una clase de plantilla, sino una plantilla de clase. Es decir, es una plantilla a partir de la cual se pueden generar clases. Area<int>
es una clase de este tipo (que es no un objeto, pero por supuesto se puede crear un objeto de esa clase de la misma manera que se pueden crear objetos de cualquier otra clase). Otra de esas clases sería Area<char>
. Tenga en cuenta que esas son clases completamente diferentes, que no tienen nada en común excepto por el hecho de que se generaron a partir de la misma plantilla de clase.
Dado Area
que no es una clase, no puede derivar la clase Rectangle
de ella. Solo puede derivar una clase de otra clase (o varias de ellas). Dado que Area<int>
es una clase, podría, por ejemplo, derivar Rectangle
de ella:
class Rectangle:
public Area<int>
{
// ...
};
Dado que Area<int>
y Area<char>
son clases diferentes, incluso puede derivar de ambas al mismo tiempo (sin embargo, al acceder a miembros de ellas, tendrá que lidiar con ambigüedades):
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
Sin embargo, debe especificar de qué clase derivar cuando defina Rectangle
. Esto es cierto sin importar si esas clases se generan a partir de una plantilla o no. Dos objetos de la misma clase simplemente no pueden tener diferentes jerarquías de herencia.
Lo que puede hacer es crear Rectangle
una plantilla también. Si tú escribes
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Tiene una plantilla Rectangle
de la que puede obtener una clase de la Rectangle<int>
que se deriva Area<int>
y una clase diferente de la Rectangle<char>
que se deriva Area<char>
.
Puede ser que desee tener un solo tipo Rectangle
para poder pasar todo tipo de Rectangle
a la misma función (que en sí misma no necesita conocer el tipo de Área). Dado que las Rectangle<T>
clases generadas al crear instancias de la plantilla Rectangle
son formalmente independientes entre sí, no funciona de esa manera. Sin embargo, puede hacer uso de la herencia múltiple aquí:
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);
}
Si es importante que su genérico Rectangle
se derive de un genérico, Area
también puede hacer el mismo truco con 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
};