Para entender os modelos, é uma grande vantagem definir a terminologia correta, porque a maneira como você fala sobre eles determina a maneira de pensar sobre eles.
Especificamente, Area
não é uma classe de modelo, mas um modelo de classe. Ou seja, é um modelo a partir do qual as classes podem ser geradas. Area<int>
é tal classe um (é não um objeto, mas é claro que você pode criar um objeto dessa classe da mesma forma que você pode criar objetos a partir de qualquer outra classe). Outra classe seria Area<char>
. Observe que essas são classes completamente diferentes, que não têm nada em comum, exceto pelo fato de que foram geradas a partir do mesmo modelo de classe.
Como Area
não é uma classe, você não pode derivar a classe Rectangle
dela. Você só pode derivar uma classe de outra classe (ou de várias delas). Como Area<int>
é uma classe, você poderia, por exemplo, derivar Rectangle
dela:
class Rectangle:
public Area<int>
{
// ...
};
Como Area<int>
e Area<char>
são classes diferentes, você pode até derivar de ambas ao mesmo tempo (no entanto, ao acessar membros delas, você terá que lidar com ambigüidades):
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
No entanto, você deve especificar de qual classe derivar ao definir Rectangle
. Isso é verdade, não importa se essas classes são geradas a partir de um modelo ou não. Dois objetos da mesma classe simplesmente não podem ter hierarquias de herança diferentes.
O que você pode fazer é criar Rectangle
um modelo também. Se você escrever
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Você tem um modelo Rectangle
do qual pode obter uma classe Rectangle<int>
que deriva de Area<int>
e uma classe diferente Rectangle<char>
que deriva Area<char>
.
Pode ser que você queira ter um único tipo Rectangle
para que possa passar todos os tipos de Rectangle
para a mesma função (que por si só não precisa saber o tipo de Área). Como as Rectangle<T>
classes geradas pela instanciação do modelo Rectangle
são formalmente independentes umas das outras, isso não funciona. No entanto, você pode usar a herança múltipla aqui:
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);
}
Se for importante que o seu genérico Rectangle
seja derivado de um genérico, Area
você também pode fazer o mesmo com 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
};