C++ cast to derived class

159,183

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:

  1. You use deprecated C-style cast. The proper way for such casts is
    static_cast<DerivedType *>(&m_baseType)
  2. The actual type of casted object is not of DerivedType (as it was defined as BaseType m_baseType; so any use of m_derivedType pointer will result in undefined behaviour.
Share:
159,183
user346443
Author by

user346443

Updated on April 07, 2020

Comments

  • user346443
    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
    Michael over 13 years
    This 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
    James Kanze over 13 years
    The 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
    Michael over 13 years
    There 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
    Code Abominator about 6 years
    So 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
    Martin York about 6 years
    @CodeAbominator If all animals were Shaveable then a ShaveTheShaveable() function seems pretty reasonable. But if only Cats 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
    Peter Bulyaki over 5 years
    I'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
    Martin York over 5 years
    @PeterBulyaki: It says /* Some virtual members */ don't know if It could be any clearer.
  • Peter Bulyaki
    Peter Bulyaki over 5 years
    True. I did not notice the comment, I was just reading the code. Then ignore my remark.