web-dev-qa-db-fra.com

Cast C ++ en classe dérivée

Comment convertir en classe dérivée? Les approches ci-dessous donnent toutes l'erreur suivante:

Impossible de convertir de BaseType en DerivedType. Aucun constructeur n'a pu prendre le type source, ou la résolution de surcharge du constructeur était ambiguë.

BaseType m_baseType;

DerivedType m_derivedType = m_baseType; // gives same error

DerivedType m_derivedType = (DerivedType)m_baseType; // gives same error

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error
45
user346443

Pensez comme ceci:

class Animal { /* Some virtual members */ };
class Dog: public Animal {};
class Cat: public Animal {};


Dog     dog;
Cat     cat;
Animal& AnimalRef1 = dog;  // Notice no cast required. (Dogs and cats are animals).
Animal& AnimalRef2 = cat;
Animal* AnimalPtr1 = &dog;
Animal* AnimlaPtr2 = &cat;

Cat&    catRef1 = dynamic_cast<Cat&>(AnimalRef1);  // Throws an exception  AnimalRef1 is a dog
Cat*    catPtr1 = dynamic_cast<Cat*>(AnimalPtr1);  // Returns NULL         AnimalPtr1 is a dog
Cat&    catRef2 = dynamic_cast<Cat&>(AnimalRef2);  // Works
Cat*    catPtr2 = dynamic_cast<Cat*>(AnimalPtr2);  // Works

// This on the other hand makes no sense
// An animal object is not a cat. Therefore it can not be treated like a Cat.
Animal  a;
Cat&    catRef1 = dynamic_cast<Cat&>(a);    // Throws an exception  Its not a CAT
Cat*    catPtr1 = dynamic_cast<Cat*>(&a);   // Returns NULL         Its not a CAT.

Revenons maintenant à votre première déclaration:

Animal   animal = cat;    // This works. But it slices the cat part out and just
                          // assigns the animal part of the object.
Cat      bigCat = animal; // Makes no sense.
                          // An animal is not a cat!!!!!
Dog      bigDog = bigCat; // A cat is not a dog !!!!

Il est très rare que vous ayez besoin d'utiliser la distribution dynamique.
C'est pourquoi nous avons des méthodes virtuelles:

void makeNoise(Animal& animal)
{
     animal.DoNoiseMake();
}

Dog    dog;
Cat    cat;
Duck   duck;
Chicken chicken;

makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);

La seule raison pour laquelle je peux penser est que si vous avez stocké votre objet dans un conteneur de classe de base:

std::vector<Animal*>  barnYard;
barnYard.Push_back(&dog);
barnYard.Push_back(&cat);
barnYard.Push_back(&duck);
barnYard.Push_back(&chicken);

Dog*  dog = dynamic_cast<Dog*>(barnYard[1]); // Note: NULL as this was the cat.

Mais si vous avez besoin de réinjecter des objets particuliers dans Dogs, il y a un problème fondamental dans votre conception. Vous devez accéder aux propriétés via les méthodes virtuelles.

barnYard[1]->DoNoiseMake();
123
Martin York

dynamic_cast devrait être ce que vous recherchez.

MODIFIER:

DerivedType m_derivedType = m_baseType; // gives same error

Ce qui précède semble essayer d'appeler l'opérateur d'affectation, qui n'est probablement pas défini sur le type DerivedType et accepter un type de BaseType.

DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error

Vous êtes sur le bon chemin ici mais l'utilisation de dynamic_cast tentera de transtyper en toute sécurité vers le type fourni et s'il échoue, un NULL sera retourné.

En allant ici en mémoire, essayez ceci (mais notez que le cast retournera NULL pendant que vous castez d'un type de base vers un type dérivé):

DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);

Si m_baseType était un pointeur et pointait réellement vers un type de DerivedType, alors dynamic_cast devrait fonctionner.

J'espère que cela t'aides!

7
Michael

Vous ne pouvez pas convertir un objet de base en un type dérivé - il n'est pas de ce type.

Si vous avez un pointeur de type de base vers un objet dérivé, vous pouvez le caster à l'aide de dynamic_cast. Par exemple:

DerivedType D;
BaseType B;

BaseType *B_ptr=&B
BaseType *D_ptr=&D;// get a base pointer to derived type

DerivedType *derived_ptr1=dynamic_cast<DerivedType*>(D_ptr);// works fine
DerivedType *derived_ptr2=dynamic_cast<DerivedType*>(B_ptr);// returns NULL
5
Michael Kohne

Tout d'abord - la condition préalable pour abattre est que l'objet que vous lancez est du type vers lequel vous lancez. La diffusion avec dynamic_cast vérifiera cette condition lors de l'exécution (à condition que l'objet converti ait certaines fonctions virtuelles) et lève bad_cast Ou renvoie le pointeur NULL en cas d'échec. Les conversions au moment de la compilation ne vérifieront rien et entraîneront simplement un comportement indéfini si cette condition préalable ne tient pas.
Analysons maintenant votre code:

DerivedType m_derivedType = m_baseType;

Ici, il n'y a pas de casting. Vous créez un nouvel objet de type DerivedType et essayez de l'initialiser avec la valeur de la variable m_baseType.

La ligne suivante n'est pas beaucoup mieux:

DerivedType m_derivedType = (DerivedType)m_baseType;

Ici, vous créez un temporaire de type DerivedType initialisé avec la valeur m_baseType.

La dernière ligne

DerivedType * m_derivedType = (DerivedType*) & m_baseType;

devrait compiler à condition que BaseType soit une classe de base publique directe ou indirecte de DerivedType. Il a quand même deux défauts:

  1. Vous utilisez une conversion de style C obsolète. La bonne façon pour ces lancers est
    static_cast<DerivedType *>(&m_baseType)
  2. Le type réel d'objet casté n'est pas de DerivedType (car il a été défini comme BaseType m_baseType; Donc toute utilisation du pointeur m_derivedType Entraînera un comportement indéfini.
2
Tadeusz Kopec