76

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
gsamaras
  • 71,951
  • 46
  • 188
  • 305
user346443
  • 4,672
  • 15
  • 57
  • 80
  • 10
    I don't believe the last one gives the same error. – sharptooth Mar 15 '11 at 14:37
  • 3
    Are you sure your DerivedType is inheriting from BaseType. Can you post more code? – Nick Mar 15 '11 at 14:38
  • 4
    If you have any background in languages in C# or Java, you should note that dynamic type information is only really used when you have pointers (e.g. BaseType *b = new DerivedType()). Otherwise, you'll end up with slicing. – Mike Bailey Mar 15 '11 at 14:44
  • For a start you **should not** be doing that anyway. Which is why you are getting errors. When done correctly (via dynamic_cast) the result should either be NULL or an exception. What are you really trying to do? – Martin York Mar 15 '11 at 14:53
  • 2
    You just can't do that, because the BaseType isn't a DerivedType. You cannot cast an Animal to be Dog, but perhaps a Dog* into an Animal*. – Bo Persson Mar 15 '11 at 14:57
  • What constructors have you declared for each type (e.g., default, copy, overloaded, etc.)? – Michael Mar 15 '11 at 15:02
  • @sharptooth: It may not give an error. But it will not always give the correct answer either. – Martin York Mar 15 '11 at 17:02

4 Answers4

186

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();
SirGuy
  • 10,660
  • 2
  • 36
  • 66
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 5
    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) – Code Abominator Jun 21 '18 at 03:13
  • 1
    @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. – Martin York Jun 21 '18 at 16:45
  • 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: https://stackoverflow.com/questions/23089511/dynamic-down-cast-to-abstract-class-c – Peter Bulyaki Feb 02 '19 at 03:54
  • @PeterBulyaki: It says `/* Some virtual members */` don't know if It could be any clearer. – Martin York Feb 02 '19 at 06:23
  • True. I did not notice the comment, I was just reading the code. Then ignore my remark. – Peter Bulyaki Feb 03 '19 at 04:23
  • why would the use of `dynamic_cast` be rare and how come casting the derived to parent be a fundamental design problem? – xyf Sep 01 '22 at 16:36
  • @xyf Because you would usually pass a "Cat" or "Dog" to a function/interface that takes an "Animal" you don't need to manually cast the object to "Animal" that is implicit. – Martin York Sep 01 '22 at 18:23
12

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
Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
9

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!

Michael
  • 786
  • 8
  • 18
  • 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. – Michael Mar 15 '11 at 15:01
  • 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. – James Kanze Mar 15 '11 at 18:51
  • 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. – Michael Mar 15 '11 at 19:18
3

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.
Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83