简体   繁体   中英

upcasting and downcasting in C++

I was trying the idea of casting in C++ using Visual Studio C++ 2010 Express and the use of dynamic_cast. But somehow, when I run it, an cat object can actually perform dog behaviour.

Seem like Dog d = (Dog )aa; got the compiler confused. Any advice?

Below is my code.

`
#include <iostream>
#include <string>

using namespace std;

class Animal {
public:
    string name ;
    Animal(string n) : name(n) {cout << "construct animal " << name << endl ;  }
    Animal() : name("none") { };
    virtual string getName() { return name ; }
    virtual ~Animal() { cout << "destruct animal " << name << endl ; }
};

class Dog: public Animal{

public:
    Dog() :Animal("") { }
    Dog(string n): Animal(n) {
        cout << "construct Dog" << endl ; 
    }
    void dogStuff() { cout << "hello woof...."; }
};

class Cat: public Animal{

public:
    Cat() :Animal("") { }
    Cat(string n): Animal(n) {
        cout << "construct Cat" << endl ; 
    }
    void catStuff() { cout << "hello meow...."; }
};

int main() { 

    Animal *aa = new Cat("Catty"); // cat upcasting to animal 
    Dog *d = (Dog*)aa; // animal downcasting to dog. ???
    cout << d->getName() << endl;
    d->dogStuff();
    Dog* dog = dynamic_cast<Dog*>(d) ;

    if(dog)  { 
        cout << "valid  cast" << endl ;
        dog->dogStuff();
        cout << dog->getName();
    }else
        cout << "invalid  cast" << endl ;

    int i ;
    cin >> i ;

    return 0;
}

output

construct animal Catty

construct Cat

Catty

hello woof....valid cast

hello woof....Catty

`

Dog *d = (Dog*)aa;

The parentheses style of type cast is called a C-style cast , because it is designed to mimic the behavior of C. In this case, the compiler performs a static_cast , which proceeds to downcast Animal* to Dog* , on the assumption that the underlying object is Dog . Because the underlying object is actually Cat , the program is ill-formed, and anything can happen, including memory corruption. C-style casts never do any run-time safety checks.

Dog* dog = dynamic_cast<Dog*>(d);

This cast doesn't actually have to do anything: It's converting from Dog* to Dog* . A run-time safety check does not have to be done, even though dynamic_cast is used, because d is assumed to be a well-formed Dog* .

Advice

Avoid the C-style casts. Make sure that any downcasts are valid. I personally don't use dynamic_cast very much, but then the responsibility is on me to only downcast properly.

Animal *aa = new Cat("Catty"); // cat upcasting to animal 
Dog *d = (Dog*)aa; // animal downcasting to dog. ???

This is undefined behaviour, you will need some knowledge on the low level implementation with v-tables to understand why the call results in a woof. Until then, know that undefined behaviour should be avoided.

Dog* dog = dynamic_cast<Dog*>(d);

Since d is already a Dog*, the compiler is probably not generating code to do RTTI and simply assigning it, hence it succeeded.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM