2009-09-30 10 views
5

Je suis en train de jeter d'un générique à l'autre, par exemple:C++ clichage Modèles avec des dérivés

myClass<MoreAbstract> anItem = myclass<DerivateFromMoreAbstract> anotherObject; 

Ou faire quelque chose comme

aFunction(anotherObject); // myclass<DerivateFromMoreAbstract> anotherObject 

où la signature AFunction est

aFunction(myClass<MoreAbstract> item); 

En fait, myClass est en fait une implémentation simplifiée de shared_ptr que j'ai trouvé en ligne. Je me demande s'il est possible de passer d'un type de pointeur à un autre en étant encapsulé.

Y a-t-il un moyen de faire un tel casting? Si oui, quelle serait la bonne façon de le faire?

Si elle aide tout le monde, VC++ me donne cette erreur:

Error 1 error C2440: 'type cast' : cannot convert from 'myClass<T>' to 'myClass<T>' 
+1

Est-ce un C++ net. génériques ou une question de modèles C++? –

+0

@Yannick: Modèles C++. – tomzx

Répondre

10

Vous ne pouvez pas effectuer de conversion statique, car ils sont incompatibles. Vous pouvez parfois créer un opérateur de forcer le type à la place

#include <iostream> 

class A { }; 

class B : public A { }; 


template<typename T> 
struct holder { 
    T* value; 

    holder (T*value) : value (value) { } 

    template < typename U > // class T : public U 
    operator holder<U>() const 
    { 
     return holder<U>(value); 
    } 
}; 


int main() 
{ 
    using namespace std; 

    B b; 

    holder<B> hb (&b); 
    holder<A> ha = hb; 

    cout << boolalpha; 

    cout << (hb.value == ha.value) << endl; 

    return 0; 
} 

Que ce soit une opération significative dépend plutôt de la sémantique de la classe de modèle - si le aFunction peut mettre quoi que ce soit dans le gestionnaire, vous ne voulez pas objet plus spécifique étant muté. Par conséquent, vous copiez d'une manière ou d'une autre, soit avec un opérateur de contrainte, soit avec un constructeur de copie de modèle et une affectation. (la coercition est moins de code mais peut entraîner la création d'objets supplémentaires si vous n'utilisez pas de paramètres de référence)

+2

Je préférerais un constructeur de conversion à un opérateur de conversion car ce dernier ne peut pas être activé ou désactivé –

+0

@Pete Kirkham: J'ai besoin de votre aide. Pourquoi avez-vous utilisé le modèle à l'intérieur de struct titulaire? Quel est son but? Dans les commentaires, vous avez écrit // classe T: public U. Qu'est-ce que cela signifie? – Destructor

3

Désolé, cela est impossible. (Eh bien, à moins que vous ne fassiez des reinterpret_cast hacks, mais vous ne voulez pas faire cela - le résultat final ne serait pas joli).

T<Base> et T<Derived> ne sont pas liés. Le compilateur ne peut pas supposer cela - rappelez-vous qu'il est tout à fait possible que T soit spécialisé pour que Derived soit quelque chose de complètement différent.

1

Les modèles en C++ ainsi que les génériques en C++ .net ne sont pas covariants.

Vérifiez this question, pourrait vous donner une idée pour une solution de contournement.

6

Les types ne sont pas convertibles par défaut de cette manière (car vous ne voulez pas que les objets le fassent). En général, vous pouvez utiliser deux approches:

Implémentez une fonction de conversion explicite, qui peut être utile pour les conversions d'exécution, par exemple boost's shared_ptr dynamic_pointer_cast. Vous finiriez avec quelque chose comme:

template <typename To, typename From> 
myclass<To> myclass_cast(const myclass<From>&) 
{ /* do a runtime cast, possibly with exceptions */ } 

La deuxième méthode est un constructeur de conversion, ce qui est bon si elle est décidable au moment de la compilation si elles sont convertable. Par exemple, si toutes les classes sont convertable de templated sur dérivés à templated sur la base, voici un constructeur qui ne fonctionne que si cela est vrai (en utilisant enable_if et boost :: type_traits):

template <typename To> 
class myclass { 
    //converting constructor 
    template <typename From> 
    myclass(const myclass<From>&, 
      typename enable_if<boost::type_traits::is_base_of<To, From> >::type* dummy = 0) 
    { } 
};