Here though we are typecasting bptr(a base pointer) into base*,the actual address stored there is derived address,so I think
the typecast should be treated like I am trying to convert derived address into base* ? No? |
As I mentioned, it does not matter, result would be still the same: a
derived object contains a
base subobject inside itself and
derived-specific data. By casting
derived* to
base*, we are returning pointer to that
base part. If we already have a pointer to base part, then no matter what actual type of object, such a conversion would always return pointer to that base part
http://puu.sh/kVFPJ/b89c19065b.png
As you mentioned it checks tun time type identification,could you mention what factors can influence this type cast and what conditions can make this typecast successfully return non null value? |
The real type of object should be either of same type you are casting it to, or its descendand.
in downcasting which means typecasting derived address into base* |
This is upcasting. It is always safe, as any child knows who his parent is. Child→Parent = upcast; Parent→Chiled = downcast. Downcasts could be dangerous as object do not know how many children they have.
there would always be extra functionality added in the derived class and it would always make it meaningless to do downcasting to convert derived address into base* |
...Or base class functionality changed. Each derived class is-a base class. This means it supports at least same operation that parent class. This allows it to be used instead of base class. And in presence of virtual functions it allows you to get different behavior depending on real type of object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
struct Animal
{
virtual void say() = 0;
virtual ~Animal() = default;
};
struct Dog : Animal
{
virtual void say() override { std::cout << "Woof\n"; }
virtual void bite() {}
};
struct Cat: Animal
{
virtual void say() override { std::cout << "Meow\n"; }
virtual void scratch() {}
};
| |
Here any Animal can say: both base class, Dog and Cat; but only Dog can bite and only Cat can scratch. If we cast some derived class pointer to base one, we could use only base class interface (say()), but it will behave according to real type of object:
1 2 3 4 5
|
Animal* zoo[] = {new Dog, new Dog, new Cat};
for(Animal* animal: zoo) {
animal->say();
delete animal;
}
|
Woof
Woof
Meow | |
Sometimes we need a extended class functionality. We need to cast downward. One way is to use a static_cast:
1 2 3 4 5 6
|
Animal* animal = new Cat;
//Works, safe
static_cast<Cat*>(animal)->scratch();
//Compiles, but does not do what you want! Dangerous!
static_cast<Dog*>(animal)->bite();
| |
As you can see, it only works properly when you sure that you are casting it to correct type. If you are not sure, use dynamic_cast, so you can check if conversion can be made:
1 2 3 4 5 6
|
Animal* animal = new Dog;
Cat* cat = dynamic_cast<Cat*>(animal);
if(cat != nullptr)
cat->scratch();
else
std::cout << "This is not a cat\n";
|
"This is not a cat\n" | |
Additional examples of how dynamic_cast works:
1 2 3 4 5 6 7 8 9 10
|
struct Hound: Dog
{};
struct Husky: Dog
{};
Animal* animal = new Husky;
dynamic_cast<Cat*>(animal); //Returns nullptr
dynamic_cast<Dog*>(animal); //Returns non-null pointer of Dog type
dynamic_cast<Husky*>(animal); //Returns non-null pointer of Husky type
dynamic_cast<Hound*>(animal); //Returns nullptr
| |