Pour comprendre les modèles, il est très utile de connaître la terminologie, car la façon dont on parle d'un modèle détermine la façon dont on le conçoit.
En particulier, Area
n'est pas un modèle de classe, mais un modèle de classe. En d'autres termes, il s'agit d'un modèle à partir duquel des classes peuvent être générées. Area<int>
est une telle classe (c'est no un objet, mais vous pouvez bien sûr créer un objet à partir de cette classe de la même manière que vous pouvez créer des objets à partir de n'importe quelle autre classe). Une autre classe de ce type serait Area<char>
. Notez qu'il s'agit de classes complètement différentes, qui n'ont rien en commun si ce n'est le fait qu'elles ont été générées à partir du même modèle de classe.
Depuis Area
n'est pas une classe, vous ne pouvez pas dériver la classe Rectangle
de celui-ci. Seule une classe peut être dérivée d'une autre classe (ou de plusieurs). Puisque Area<int>
est une classe, vous pourriez, par exemple, dériver Rectangle
de celui-ci :
class Rectangle:
public Area<int>
{
// ...
};
Depuis Area<int>
y Area<char>
sont des classes différentes, vous pouvez même dériver des deux en même temps (cependant, lorsque vous accéderez à leurs membres, vous devrez gérer des ambiguïtés) :
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
Cependant, vous devez préciser de quelle classe vous voulez dériver lorsque vous définissez Rectangle
. Cela est vrai, que ces classes soient générées à partir d'un modèle ou non. Deux objets de la même classe ne peuvent tout simplement pas avoir des hiérarchies d'héritage différentes.
Ce que vous pouvez faire, c'est Rectangle
un modèle également. Si vous écrivez
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Vous avez un modèle Rectangle
à partir de laquelle vous pouvez obtenir une classe Rectangle<int>
qui découle de Area<int>
et une autre classe Rectangle<char>
qui découle de Area<char>
.
Il se peut que vous souhaitiez disposer d'un seul type Rectangle
afin que vous puissiez passer toutes sortes de Rectangle
à la même fonction (qui elle-même n'a pas besoin de connaître le type de zone). Puisque la fonction Rectangle<T>
générées par l'instanciation du modèle Rectangle
sont formellement indépendants l'un de l'autre, cela ne fonctionne pas de cette manière. Cependant, vous pouvez utiliser l'héritage multiple dans ce cas :
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);
}
S'il est important que votre produit générique Rectangle
est dérivé d'un modèle générique Area
vous pouvez faire la même chose avec Area
aussi :
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
};