-
Notifications
You must be signed in to change notification settings - Fork 0
Cplus plus
class Parent {
public:
void sleep() {}
};
class Child: public Parent {
public:
void gotoSchool(){}
};
int main( )
{
Parent parent;
Child child;
// upcast - implicit type cast allowed
Parent *pParent = &child;
// downcast - explicit type case required
Child *pChild = (Child *) &parent;
pParent -> sleep();
pChild -> gotoSchool();
return 0;
}
Upcasting allows us to treat a derived type as though it were its base type. That's how we decouple ourselves from knowing about the exact type we are dealing with.
The opposite process, converting a base-class pointer (reference) to a derived-class pointer (reference) is called downcasting. Downcasting is not allowed without an explicit type cast. The reason for this restriction is that the is-a relationship is not, in most of the cases, symmetric. A derived class could add new data members, and the class member functions that used these data members wouldn't apply to the base class.
Ref: Upcasting and Downcasting
As described in Callable, when invoking a pointer to non-static member function or pointer to non-static data member, the first argument has to be a reference or pointer (including, possibly, smart pointer such as std::shared_ptr and std::unique_ptr) to an object whose member will be accessed.
class MyClass {
private:
//just shorthand to avoid long typing
typedef std::function<void (float result)> TCallback;
//this function takes long time
void longRunningFunction(TCallback callback)
{
//do some long running task
//...
//callback to return result
callback(result);
}
//this function gets called by longRunningFunction after its done
void afterCompleteCallback(float result)
{
std::cout << result;
}
public:
int longRunningFunctionAsync()
{
//create callback - this equivalent of safe function pointer
auto callback = std::bind(&MyClass::afterCompleteCallback,
this, std::placeholders::_1);
//normally you want to start below function on seprate thread,
//but for illustration we will just do simple call
longRunningFunction(callback);
}
};
Ref: a good example from stackoverflow.com
// https://www.journaldev.com/37371/static-cast-in-c
#include <iostream>
using namespace std;
class BaseClass {
public:
int a, b;
BaseClass(int val_a = 200, int val_b = 200) {
a = val_a; b = val_b;
}
void print_obj() {
cout<<"BaseClass Object: a = "<< a <<" , b = " <<b<< endl;
}
~BaseClass() {
}
};
// We can cast only if the inheritance is public
class DerivedClass : public BaseClass {
public:
int c;
DerivedClass(int val_c = 100) { c = val_c; }
void print_obj() {
cout << "DerivedClass Object: a = " << a << " , b = " << b << " , c = " << c << endl;
}
~DerivedClass() {
}
};
int main() {
BaseClass* base_obj = new BaseClass(20, 25);
DerivedClass* derived_obj = new DerivedClass(10);
base_obj->print_obj();
derived_obj->print_obj();
// Cast downwards - Can do this only if you don't use Virtual Inheritance
DerivedClass* base_to_derived = static_cast<DerivedClass*>(base_obj);
cout << "After casting BaseClass object to DerivedClass, ";
base_to_derived->print_obj();
// Can cast upwards - Redundant
BaseClass* derived_to_base = static_cast<BaseClass*>(derived_obj);
// or "BaseClass* derived_to_base = (derived_obj);" gives the same results, that's why it is called "redundant"
cout << "After casting DerivedClass object to BaseClass, ";
derived_to_base->print_obj();
// Free the pointers
delete base_obj;
delete derived_obj;
return 0;
}
/*
BaseClass Object: a = 20 , b = 25
DerivedClass Object: a = 200 , b = 200 , c = 10
After casting BaseClass object to DerivedClass, DerivedClass Object: a = 20 , b = 25 , c = 0
After casting DerivedClass object to BaseClass, BaseClass Object: a = 200 , b = 200
*/
How do we use the dynamic_cast?
void f(Parent* p) {
Child *ptr = dynamic_cast<Child*>(p);
if(ptr) {
// we can safely use ptr
}
}
In the code, if (ptr) is of the type Child or else derived directly or indirectly from the type Child, the dynamic_cast converts the pointer p to a pointer of type Child. Otherwise, the expression evaluates to 0, the null pointer.
In other words, we want to check if we can use the passed in pointer p before we do some operation on a child class object even though it's a pointer to base class.
The need for dynamic_cast generally arises because we want perform derived class operation on a derived class object, but we have only a pointer-or reference-to-base. -Scott Meyers
[Ref: upcasting and downcasting]https://www.bogotobogo.com/cplusplus/upcasting_downcasting.php
// https://www.journaldev.com/37371/static-cast-in-c
#include <iostream>
using namespace std;
class BaseClass {
public:
int a, b;
BaseClass(int val_a = 200, int val_b = 200) {
a = val_a; b = val_b;
}
virtual void print_obj() {
cout<<"BaseClass Object: a = "<< a <<" , b = " <<b<< endl;
}
~BaseClass() { }
};
class DerivedClass : public BaseClass {
public:
int c;
DerivedClass(int val_c = 100) { c = val_c; }
void print_obj() {
cout << "DerivedClass Object: a = " << a << " , b = " << b << " , c = " << c << endl;
}
~DerivedClass() { }
};
int main() {
BaseClass* base_obj = new BaseClass(20, 25);
DerivedClass* derived_obj = new DerivedClass(10);
BaseClass* base_test = new DerivedClass(11);
base_obj->print_obj();
derived_obj->print_obj();
// Downcasting - does not work, since **base_obj** is created from "new BaseClass"
DerivedClass* base_to_derived = dynamic_cast<DerivedClass*>(base_obj);
if (base_to_derived == nullptr)
cout << "After casting BaseClass object to DerivedClass, Error\n";
else {
cout << "SHOULD NOT REACH HERE";
}
// Downcasting - works, since **base_test** is created from "new DerivedClass"
DerivedClass* test = dynamic_cast<DerivedClass*>(base_test);
if (test == nullptr)
cout << "SHOULD NOT REACH HERE";
else {
cout << "After casting BaseClass object to DerivedClass, ";
test->print_obj();
}
// Upcasting - redundant
BaseClass* derived_to_base = dynamic_cast<BaseClass*> (derived_obj);
cout << "After casting DerivedClass object to BaseClass, ";
derived_to_base->print_obj();
delete base_obj;
delete derived_obj;
return 0;
}
/*
BaseClass Object: a = 20 , b = 25
DerivedClass Object: a = 200 , b = 200 , c = 10
After casting BaseClass object to DerivedClass, Error
After casting BaseClass object to DerivedClass, DerivedClass Object: a = 200 , b = 200 , c = 11
After casting DerivedClass object to BaseClass, DerivedClass Object: a = 200 , b = 200 , c = 10
*/