resolucion - polimorfismo c++
Lanzamiento de C++ a la clase derivada (4)
¿Cómo puedo lanzar a una clase derivada? Los enfoques a continuación dan el siguiente error:
No se puede convertir de BaseType a DerivedType. Ningún constructor podría tomar el tipo de fuente, o la resolución de sobrecarga del constructor era ambigua.
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
En primer lugar, el requisito previo para Downcast es que el objeto que estás lanzando sea del tipo al que estás lanzando. Casting con dynamic_cast verificará esta condición en tiempo de ejecución (siempre que el objeto casted tenga algunas funciones virtuales) y lanzará bad_cast
o devolverá el puntero NULL
en caso de falla. Los moldes de tiempo de compilación no verifican nada y solo generarán un comportamiento indefinido si este requisito previo no se cumple.
Ahora analizando tu código:
DerivedType m_derivedType = m_baseType;
Aquí no hay casting. Está creando un nuevo objeto de tipo DerivedType
e intenta inicializarlo con el valor de la variable m_baseType.
La siguiente línea no es mucho mejor:
DerivedType m_derivedType = (DerivedType)m_baseType;
Aquí está creando un tipo DerivedType
temporal inicializado con el valor de m_baseType
.
La última línea
DerivedType * m_derivedType = (DerivedType*) & m_baseType;
debería compilarse siempre que BaseType
sea una clase base pública o indirecta de DerivedType
. Tiene dos defectos de todos modos:
- Usas el estilo C obsoleto. La forma correcta para tales moldes es
static_cast<DerivedType *>(&m_baseType)
- El tipo real de objeto emitido no es de DerivedType (como se definió como
BaseType m_baseType;
por lo que cualquier uso del punterom_derivedType
dará como resultado un comportamiento indefinido.
No puede convertir un objeto base en un tipo derivado; no es de ese tipo.
Si tiene un puntero de tipo base para un objeto derivado, entonces puede convertir ese puntero usando dynamic_cast. Por ejemplo:
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
Piensa así:
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.
Ahora mirando hacia atrás en su primera declaración:
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 !!!!
Raramente deberías necesitar usar un cast dinámico.
Es por eso que tenemos métodos virtuales:
void makeNoise(Animal& animal)
{
animal.DoNoiseMake();
}
Dog dog;
Cat cat;
Duck duck;
Chicken chicken;
makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);
La única razón por la que puedo pensar es si almacenaste tu objeto en un contenedor de clase 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.
Pero si necesita devolver objetos particulares a Perros, entonces hay un problema fundamental en su diseño. Debería acceder a las propiedades a través de los métodos virtuales.
barnYard[1]->DoNoiseMake();
dynamic_cast debería ser lo que estás buscando.
EDITAR:
DerivedType m_derivedType = m_baseType; // gives same error
Lo anterior parece estar intentando invocar al operador de asignación, que probablemente no está definido en el tipo DerivedType y que acepta un tipo de BaseType.
DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error
Está en el camino correcto aquí, pero el uso de dynamic_cast intentará transmitir de forma segura al tipo suministrado y, si falla, se devolverá un NULL.
Continuando con la memoria aquí, intente esto (pero tenga en cuenta que el molde arrojará NULL mientras está lanzando desde un tipo base a un tipo derivado):
DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);
Si m_baseType era un puntero y apuntaba a un tipo de DerivedType, entonces el dynamic_cast debería funcionar.
¡Espero que esto ayude!