1

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

`

aDeveloper
  • 11
  • 2
  • 1. `using std;` is a bad idea. Google that. 2. Read up on `const` and references. . For example `Cat(string n)` -> `Cat(const string*&n)` saves on the copy – Ed Heal Apr 26 '18 at 02:09
  • 1
    Downcasting to the wrong derived type is undefined behavior. – Barmar Apr 26 '18 at 02:12

2 Answers2

2
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.

Jack C.
  • 744
  • 3
  • 7
1
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.

Jay Wai Tan
  • 169
  • 7