Pour comprendre les modèles, il est extrêmement avantageux de clarifier la terminologie, car la façon dont vous en parlez détermine la façon de les penser.
Plus précisément, ce Area
n'est pas une classe de modèle, mais un modèle de classe. Autrement dit, il s'agit d'un modèle à partir duquel des classes peuvent être générées. Area<int>
est une telle classe (ce n'est pas un objet, mais bien sûr, vous pouvez 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 serait Area<char>
. Notez que ce sont des classes complètement différentes, qui n'ont rien de commun si ce n'est qu'elles ont été générées à partir du même modèle de classe.
Puisque ce Area
n'est pas une classe, vous ne pouvez pas en dériver la classe Rectangle
. Vous ne pouvez dériver une classe qu'à partir d'une autre classe (ou de plusieurs d'entre elles). Puisque Area<int>
est une classe, vous pouvez, par exemple, en dériver Rectangle
:
class Rectangle:
public Area<int>
{
// ...
};
Puisque Area<int>
et Area<char>
sont des classes différentes, vous pouvez même dériver des deux en même temps (cependant, lorsque vous accédez à leurs membres, vous devrez faire face à des ambiguïtés):
class Rectangle:
public Area<int>,
public Area<char>
{
// ...
};
Cependant, vous devez spécifier de quelle classe 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.
Vous pouvez également créer Rectangle
un modèle. Si vous écrivez
template<typename T> class Rectangle:
public Area<T>
{
// ...
};
Vous avez un modèle à Rectangle
partir duquel vous pouvez obtenir une classe Rectangle<int>
qui dérive Area<int>
et une classe différente Rectangle<char>
qui dérive Area<char>
.
Il se peut que vous souhaitiez avoir un seul type Rectangle
pour pouvoir passer toutes sortes de choses Rectangle
à la même fonction (qui elle-même n'a pas besoin de connaître le type Area). Étant donné que les Rectangle<T>
classes générées par l'instanciation du modèle Rectangle
sont formellement indépendantes les unes des autres, cela ne fonctionne pas de cette façon. Cependant, vous pouvez utiliser l'héritage multiple ici:
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 générique Rectangle
soit dérivé d'un générique, Area
vous pouvez également faire la même chose 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
};