C++ cast to derived class
Solution 1
Think like this:
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.
Now looking back at your first statement:
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 !!!!
You should very rarely ever need to use dynamic cast.
This is why we have virtual methods:
void makeNoise(Animal& animal)
{
animal.DoNoiseMake();
}
Dog dog;
Cat cat;
Duck duck;
Chicken chicken;
makeNoise(dog);
makeNoise(cat);
makeNoise(duck);
makeNoise(chicken);
The only reason I can think of is if you stored your object in a base class container:
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.
But if you need to cast particular objects back to Dogs then there is a fundamental problem in your design. You should be accessing properties via the virtual methods.
barnYard[1]->DoNoiseMake();
Solution 2
You can't cast a base object to a derived type - it isn't of that type.
If you have a base type pointer to a derived object, then you can cast that pointer around using dynamic_cast. For instance:
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
Solution 3
dynamic_cast should be what you are looking for.
EDIT:
DerivedType m_derivedType = m_baseType; // gives same error
The above appears to be trying to invoke the assignment operator, which is probably not defined on type DerivedType and accepting a type of BaseType.
DerivedType * m_derivedType = (DerivedType*) & m_baseType; // gives same error
You are on the right path here but the usage of the dynamic_cast will attempt to safely cast to the supplied type and if it fails, a NULL will be returned.
Going on memory here, try this (but note the cast will return NULL as you are casting from a base type to a derived type):
DerivedType * m_derivedType = dynamic_cast<DerivedType*>(&m_baseType);
If m_baseType was a pointer and actually pointed to a type of DerivedType, then the dynamic_cast should work.
Hope this helps!
Solution 4
First of all - prerequisite for downcast is that object you are casting is of the type you are casting to. Casting with dynamic_cast will check this condition in runtime (provided that casted object has some virtual functions) and throw bad_cast
or return NULL
pointer on failure. Compile-time casts will not check anything and will just lead tu undefined behaviour if this prerequisite does not hold.
Now analyzing your code:
DerivedType m_derivedType = m_baseType;
Here there is no casting. You are creating a new object of type DerivedType
and try to initialize it with value of m_baseType variable.
Next line is not much better:
DerivedType m_derivedType = (DerivedType)m_baseType;
Here you are creating a temporary of DerivedType
type initialized with m_baseType
value.
The last line
DerivedType * m_derivedType = (DerivedType*) & m_baseType;
should compile provided that BaseType
is a direct or indirect public base class of DerivedType
. It has two flaws anyway:
- You use deprecated C-style cast. The proper way for such casts is
static_cast<DerivedType *>(&m_baseType)
- The actual type of casted object is not of DerivedType (as it was defined as
BaseType m_baseType;
so any use ofm_derivedType
pointer will result in undefined behaviour.
user346443
Updated on April 07, 2020Comments
-
user346443 about 4 years
How can i cast to a derived class? The below approaches all give the following error:
Cannot convert from BaseType to DerivedType. No constructor could take the source type, or constructor overload resolution was ambiguous.
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
-
Michael over 13 yearsThis smells of a lack of default constructors for each of the types. This might be at the issue when attempting to cast and receiving the noted error.
-
James Kanze over 13 yearsThe first line is not trying to invoke the assignment operator. It is trying to convert m_baseType to type DerivedType, then copy that using the copy constructor.
-
Michael over 13 yearsThere is no copy constructor call in the first line. If anything, the default constructor of the DerivedType would be invoked, followed by an attempt to invoke an assignment operator, if one existed with the BaseType as the argument.
-
Code Abominator about 6 yearsSo a function like HerdAllTheCats(barnYard) makes no sense and shouldn't be done? ShaveTheShaveable(barnYard) would be right out of the question? (obviously C++ would make that very hard to do, but it's a common use of OOP)
-
Martin York about 6 years@CodeAbominator If all animals were
Shaveable
then aShaveTheShaveable()
function seems pretty reasonable. But if onlyCats
were shavable then no it does not sound reasonable not OOP. But this is way to abstract a discussion. You should ask a question and get feedback. -
Peter Bulyaki over 5 yearsI'd point out that without defining the body of these classes the above example is a bit dangerous, the inheritance by itself does not guarantee that your classes are going to be polymorphic. And dynamic_cast only works with polymorphic classes, which means Animal must contain at least one virtual member function (as a minimum a virtual destructor). Without that you will get the following error from the compiler: "the operand of a runtime dynamic_cast must have a polymorphic class type". Also see here: stackoverflow.com/questions/23089511/…
-
Martin York over 5 years@PeterBulyaki: It says
/* Some virtual members */
don't know if It could be any clearer. -
Peter Bulyaki over 5 yearsTrue. I did not notice the comment, I was just reading the code. Then ignore my remark.