135 votes

Hériter d'une classe modèle en c++

Supposons que nous ayons une classe modèle Area qui possède une variable membre T area , a T getArea() et un void setArea(T) les fonctions des membres.

Je peux créer un Area d'un objet d'un type spécifique en tapant Area<int> .

J'ai maintenant une classe Rectangle qui hérite de la Area classe. Depuis le Rectangle n'est pas un modèle, je ne peux pas taper Rectangle<int> .

Comment puis-je spécialiser les Area type pour Rectangle objets ?

EDIT : Désolé, j'ai oublié de clarifier - ma question est de savoir s'il est possible d'hériter de Area sans la spécialiser, de sorte qu'elle n'est pas héritée comme Area of ints mais comme Area Rectangle dont on peut spécialiser les types.

314voto

celtschk Points 9699

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
};

31voto

Stuart Golodetz Points 12679

Essayez-vous simplement de dériver de la Area<int> ? Dans ce cas, procédez comme suit :

class Rectangle : public Area<int>
{
    // ...
};

EDIT : Suite à la clarification, il semble que vous essayez en fait de faire des Rectangle un modèle également, auquel cas la procédure suivante devrait fonctionner :

template <typename T>
class Rectangle : public Area<T>
{
    // ...
};

11voto

ldanko Points 487
class Rectangle : public Area<int> {
};

10voto

pezcode Points 2596

Faire de Rectangle un modèle et transmettre le nom du modèle à Area :

template <typename T>
class Rectangle : public Area<T>
{

};

7voto

Rectangle devra être un modèle, sinon c'est un seul type . Il ne peut pas être un non-modèle alors que sa base l'est magiquement. (Sa base peut être un modèle instanciation bien que vous sembliez vouloir maintenir la fonctionnalité de la base comme modèle .)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X