2010-11-04 4 views
4

je 3 classe qui dérive de l'autre:C++ coulée de modèle sur les classes dérivées

class Basic{ 
... 
} 

class Extended : public Basic{ 
... 
} 

class Full : public Extended{ 
... 
} 

J'ai une classe de modèle qui détient 5-5 de cette classe:

template <class T> 
    class group{ 
    public: 
      ... 
    private: 
     T one, two, three, four, five; 
    }; 

group<Basic> basicGroup; 
group<Extended> extendedGroup; 
group<Full> fullGroup; 

Puis-je facilement transtyper par exemple fullGroup en basicGroup ou extendedGroup en basicGroup? (Je veux juste lancer vers le haut)

+0

Probablement, vous devez faire circuler les itérateurs de ces groupes, pas les groupes eux-mêmes.Dans ce cas, le moulage ne serait pas nécessaire – Alsk

Répondre

3

Une solution serait de créer une sorte de vue classe qui peut envelopper un groupe, et expose les objets individuels comme des instances de base de classe:

template <class T> 
class group{ 
public: 
    const T & getOne() { return one; } 
private: 
    T one, two, three, four, five; 
}; 

template <class T, U> 
class group_view { 
public: 
    group_view(group<T> & inner) : innerGroup(inner) {} 

    const U & getOne() { return dynamic_cast< const U &>(one); } 
private: 
    group<T> & innerGroup; 
}; 

Vous pouvez l'utiliser comme ceci:

group<Full> fullGroup; 
group_view<Full, Extended> extendedGroupView(fullGroup); 

Si vous extrayez l'interface publique de group dans une classe de base abstraite, vous pouvez même utiliser group_view de la polymorphically.

0

Un modèle de classe avec un paramètre différent est considéré par le système de type C++ comme un type entièrement différent. Ainsi, un group<Basic> n'est pas du même type qu'un group<Extended>, et vous ne pouvez pas effectuer de cast entre ces deux types en toute sécurité.

Vous pouvez uniquement extruder vers le haut sur des instances individuelles de Full ou Extended.

0

Vous ne pouvez pas directement convertir des groupes de ce type. Ce que vous devez faire est soit

  1. faire une classe de groupe générique avec One-cinq étant pointeurs à base
  2. Faire FullGroup tirer de ExtendedGroup, qui découlerait de basicGroup.
0

Vous ne pouvez pas convertir un conteneur d'un type en conteneur d'un autre type. Et dans ce cas, le groupe est essentiellement un conteneur ...

Vous devez copier un à un les éléments.

2

Non, ces trois types ne sont pas liés, vous ne pouvez pas les convertir.

Un bon exemple pour comprendre pourquoi est: imaginez que vous avez un std::list<Dog>, où Dog hérite de Animal. Vous pouvez chose il est naturel de considérer que le std::list<Dog> peut être moulé dans un std::list<Animal>; mais qu'arriverait-il avec ce code?

std::list<Dog> dogList; 
// ... fill dogList as appropriate 
std::list<Animal> animalList = dogList; // Should this be legal? 
Animal aml = animalList.get(); // Fine; you get a Dog, which is an Animal 
animalList.insert(Cat()); // Aww: you are trying to add a Cat to a Dog list! 
+0

Oui et non, il y a toujours une faille dans le système de types à cet égard car dans l'OO parfait vous auriez une ReadOnlyList dont une ReadOnlyList serait dérivée. Bien sûr, la liste doit être créée quelque part où elle est accessible en écriture et ReadOnlyList peut ne pas avoir la "propriété" des données, mais cela peut être un casse-tête à certains moments que ceux-ci ne sont pas liés, en particulier dans les hiérarchies. – CashCow

+0

@CashCow: Je ne veux pas dire que ce mécanisme ne peut pas être amélioré, mais actuellement C++ fonctionne de cette façon et c'est la raison pour laquelle. Le mécanisme in-out introduit en C# 4.0, où vous pouvez spécifier la covariance ou la contravariance pour chaque paramètre de modèle, est une bonne amélioration. Mais cela ne fonctionne pas en C++. – Gorpik

+0

Notez que mon ReadOnlyList ne doit pas nécessairement être une collection, il doit juste être un moyen de lire une collection. Donc, il pourrait être const_iterator_range . Le problème de co-variance que j'ai trouvé être plus un problème dans un modèle d'usine où, dans le modèle ci-dessus, une usine qui crée Full dans l'axample est un type à la fois d'une usine et une usine (dans un certain sens) ainsi qu'une Usine car il va vous créer l'objet de votre type requis – CashCow

0

La plupart du temps, vous ne voulez pas de distribution dynamique et ne vous souciez pas du type que vous avez en dessous. Vous avez une opération que vous voulez effectuer de manière polymorphique sur votre classe de base et vous l'appelez simplement. Notez toutefois que votre modèle de groupe contient des instances de la classe, et non des pointeurs/pointeurs partagés. Ainsi vous ne pouvez pas ajouter un Full ou un Extended à un groupe d'une classe inférieure sans le découper.

Questions connexes