C++ Cast to Derived Class

C++ cast to derived class

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();

In C++, why does casting to reference of derived type work?

Because the implicit conversion from A to B doesn't exist, and you didn't define an explicit one either.

Reference casting, on the other hand, is valid because it is allowed for inherited types. More precisely, you can cast both ways between different classes in the same inheritance hierarchy. Same goes for pointers. The related concept is called polymorphism, if you'd like some pointers for further study.

Do note, however, that it only makes sense for an object that is of type Bto be cast to B. E. g.:

B b;
A& aRef = B; // equivalent of A& ref = (A&)B;
B& bRef = (B&)aRef;

What you did will fail at runtime as soon as you try to access some data or method of B that does not exist in A. Because your actual object is A, not B.

Upcasting (from an descendant to an ascendant) is always safe because any object of a class that inherits the base class is a valid base object. The downcasting, however, is dangerous for the exact reason I explained above, and should never be done using a C-style cast. Instead, use dynamic_cast:

B b;
A& aRef = B;
B& bRef = dynamic_cast<B&>(aRef);

dynamic_cast uses RTTI (run-time type information) to validate the operation and will throw an std::bad_cast exception if the conversion is not valid. This is unlike dynamic_casting pointers, in which case the cast returns nullptr instead of throwing an exception.

Cast base class object to derived class

Use dynamic_cast:

Animal& animal = getAnimalFromStack();    
if(Dog *d = dynamic_cast<Dog*>(&animal))
{
// You have a dog pointer, use *d ...

}

Is it safe to cast a class to a derived class that just adds additional functions?

No, this isn't safe. The behaviour of the program is undefined.

Static casting to a derived type is safe only when the dynamic type of the object is that derived type (or a further derived type).

Can we convert a base class pointer to a derived class pointer without knowing its real type?

The thing is: You need to know the type of each variable at compile time. Hence you cannot have a magical function f that takes an A* a and returns either B* or C* based on the runtime information of the actual type of the object pointed to by a. Even for the the following example the function B::f will be called but the return type will be of type A* since this is determined at compile time.

#include <iostream>
struct A {
virtual A* get_ptr() { std::cout << "A!\n"; return this; }
virtual ~A() {}
};

struct B: A {
B* get_ptr() { std::cout << "B!\n"; return this; }
};

void f(A*) { std::cout << "But here A!\n";}

void f(B*) { std::cout << "But here B!\n";}

int main() {
B b;
A* a = &b;
f(a->get_ptr());
}

Will print B! (since it is virtual) and then call the A* (since the compiler assumes that a->get_ptr() returns a A*) overload.

What you can do is:

  • Switch on an enum that you store in the object that corresponds to its type.
  • Trial and error with dynamic_cast.

Addendum: You will probably not need to cast a pointer to the object you have to the actual type of the object, since you can (as done above) just call the virtual functions and those will call the functions belonging to the actual type of your object. Hence, when you think that you need to do the cast as you described, think again, you probably will not need it.

If you still think you need it, reconsider your design decisions, you are probably doing something very weird.

how to cast a const base class pointer into the derived class

When you do

int res1 = ((Scalar<int>*)base)->get();

you do what is called a c-style cast. This works because c-style casts don't do any checking and ignore the casting away of const. They just cast the source type to the destination regardless of any consequences.

On the other hand static_cast actually checks what you are doing and sees you are trying to cast the constness of base away. That isn't allowed by any cast except const_cast so you get an error. We could use that here to get rid of the constness but that isn't needed. What you can do is just cast to a const Scalar<int>* using

int res2 = static_cast<const Scalar<int>*>(base)->get();

Convert base class to derived class

No, there's no built-in way to convert a class like you say. The simplest way to do this would be to do what you suggested: create a DerivedClass(BaseClass) constructor. Other options would basically come out to automate the copying of properties from the base to the derived instance, e.g. using reflection.

The code you posted using as will compile, as I'm sure you've seen, but will throw a null reference exception when you run it, because myBaseObject as DerivedClass will evaluate to null, since it's not an instance of DerivedClass.

c++ design: cast from base to derived class with no extra data members

Here is why I would not use this technique:

  1. It is a violation of the Standard and causes the behavior to be undefined. It is probably true that this works nearly all the time, but you can't rule out problems in the future. Compilers have been seen to make use of undefined behavior in optimizations, much to the disadvantage of the unsuspecting programmer. And you can't predict when and under what circumstances this will happen.

  2. You can't guarantee that neither you nor a team mate will ever add some data members to the derived type. Your class hierarchy will grow and more code will be added over time; at some point it may not be obvious to you or another programmer that adding an innocent data member to the derived type (even temporarily, perhaps for some debugging purpose) can spell disaster.

  3. There are clean and legal alternatives, for example using wrappers based on references:

    #include <iostream>

    struct Elem
    { };

    struct ElemWrapper
    {
    Elem &elem_;

    ElemWrapper(Elem &elem) : elem_(elem)
    { }
    };

    struct ElemWrapper1 : ElemWrapper
    {
    using ElemWrapper::ElemWrapper;

    void foo()
    { std::cout << "foo1" << std::endl; }
    };

    struct ElemWrapper2 : ElemWrapper
    {
    using ElemWrapper::ElemWrapper;

    void foo()
    { std::cout << "foo2" << std::endl; }
    };

    int main()
    {
    Elem e;

    ElemWrapper1(e).foo();

    return 0;
    }

c++ - converting a base class pointer to a derived class pointer

You must change the base type to be polymorphic:

class Base {
public:
Base() {};
virtual ~Base(){};
};

To cast from some supertype to some derived type, you should use dynamic_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

Using dynamic_cast here checks that the typecast is possible. If there is no need to do that check (because the cast cannot fail), you can also use static_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);


Related Topics



Leave a reply



Submit