Reputation: 136
Let's say I have a Base class Employee
and an derived class Manager
, like below:
class Employee
{
public:
string Name;
};
class Manager : public Employee
{
public:
string Designation;
};
While implementing some function like below:
Employee* SomeFunction(bool SomeCondition)
{
Employee *Emp = NULL;
if (SomeCondition)
{
//Code goes here : Both Implementation 1 and 2 work fine!
}
return Emp;
}
When SomeCondition
is true, I want to return a non-null object of type Manager
. In such a scenario, both below pieces of code seem to fit the bill:
Implementation 1:
Manager *Mng = new Manager;
Mng->Name = "Adam";
Mng->Designation = "BOSS";
Emp = Mng;
Implementation 2:
Emp = new Manager;
Manager *Mng = (Manager*)Emp;
Mng->Name = "Adam";
Mng->Designation = "BOSS";
Since both work just fine, I would like to know which one among the two is the more efficient one?
Which one is using the concept of Polymorphism?
Is the type casting in Implementation 2 a down-cast? Is it good practice?
Upvotes: 0
Views: 1836
Reputation: 1630
While I see some reasons behind your questions, I think you need to improve the your example
you are saying that you need to return a non-null object of type "Manager", while your define "SomeFunction(bool SomeCondition)" to return "Employee".
if you are indeed going to return "Employee" object why bothering initializing "Designation" while you will not be able to access it later. For example:
cout << SomeFunction(true)->Designation(); // error !
So, I'm not sure what do mean by saying your examples work fine, since the context is not clear.
** Comparing Implementation 1 and 2 / About dynamic casting
While both examples can improve, I think Implementation 1 is slightly better. In both cases you do dynamic casting. However, in Implementation 1, you do an implicit upcasting in "Emp = Mng;", while in Implementation 2 you do downcasting in "Manager Mng = (Manager)Emp;".
In general you should avoid casting (especially the downcasting since it's not that safe all the time compared with upcasting), and if you have to you should use C++ style casting (e.g. dynamic_cast). See the example in https://www.tutorialcup.com/cplusplus/upcasting-downcasting.htm
A better solution is to use virtual functions in order to avoid casting and make room to add more objects types beside "Manager". For example, your header may look like:
class Employee
{
public:
virtual void setDesignation(const string & d) = 0;
virtual string getDesignation() = 0;
};
class Manager : public Employee
{
public:
virtual void setDesignation (const string & d) {Designation=d;}
virtual string getDesignation() {return Designation;}
private:
string Designation;
};
and your function may look like:
Employee* SomeFunction(bool SomeCondition)
{
Employee *Emp = NULL;
if (SomeCondition)
{
Emp = new Manager;;
Emp->setDesignation("BOSS");
}
return Emp;
}
then if you want to access the Designation later, you can do
cout << SomeFunction(true)->getDesignation();
** About Polymorphism
you don't use any Polymorphism in both examples. This is becuase you don't use any function that is type-specific, and so your runtime behaviour doesn't vary depending on the "Employee" object (you are merely using one object type "Manager" anyways !). See the example in http://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm
Upvotes: 1
Reputation: 7099
Both of your implementations do what you want them to, however the second one is very bad practice.
First, let's clear up a misconception you seem to have: In your second implementation, you're not doing what is usually considered a downcast. You're using a C-style cast (see http://en.cppreference.com/w/cpp/language/explicit_cast), which will, among casting away things such as const
, happily cast any pointer to a Manager*
. For example, you might just as well do
Manager *Mng = (Manager*) new Employee; // not a good idea
or even
Manager *Mng = (Manager*) new int; // now, this is really bad...
As a general rule, you should never use C-style casts in C++.
You can do a safe downcast in C++ by using dynamic_cast
:
Manager *Mng = dynamic_cast<Manager*>(ptr_to_manager); // will return a pointer to the Manager object
Manager *Mng = dynamic_cast<Manager*>(ptr_to_employee); // will return nullptr
Still, there is runtime overhead needed to check whether your cast is actually safe (ie, distinguish the first case in the example from the second). The need for a downcast is, by the way, usually an indication of bad design.
In short, the first implementation is the easier and obvious way to go: no need for an downcast, safe or unsafe.
Upvotes: 1