Reputation: 81
I have this class structure where classD and classE grandparents are the same
classB : classA;
classC : classA;
classD : classB;
classE : classC;
then I have a function which requires to pass an object classF
classF : classA;
function(classF *func);
Is it possible to pass an object of type classD and classE to function which requires type classF? sample implementation as below: Is it possible to just cast both to their common grandparent?
classD *d = new classD();
classE *e = new classE();
classA *func = (classA*)d;
function(func);
func = (classA*)e;
function(func);
Upvotes: 1
Views: 121
Reputation: 8603
No, no and another time no.
The line that simply doesn't pass muster is this:
function(func);
This requires a downcast, i.e. - a cast from a parent class to its subclass. A downcast will not happen implicitly, which means the line will not compile (but had you provided compiling code, you would already know that). The following would compile:
function((classF*)func);
but you shouldn't use it. A downcast's result is undefined unless that reference originally belonged to that type. So, this is okay:
classF *f = new classF();
func = (classA*) f;
function((classF*)func);
But this is not:
classB *b = new classB();
func = (classA*) b;
function((classF*)func);
Edited to add
If the downcast is performed using the dedicated C++ cast operator dynamic_cast
, then the code, at run time, makes sure that the down cast is correct. So:
classF *f = new classF();
func = (classA*) f;
classF *newf = dynamic_cast<classF *>(func); // Okay
classB *b = new classB();
func = (classA*) b;
newf = dynamic_cast<classF *>(func); // newf is now NULL
This allows run time checking that you have not made a mistake.
Personally, I like never relying on this for actual design, only for verification. In such a case, it is better to dynamic cast references rather than pointer. Dynamic casting an incorrect pointer results in NULL. Dynamic casting an incorrect reference throws an exception:
classF *f = new classF();
func = (classA*) f;
classF *newf = &dynamic_cast<classF &>(*func); // Okay
classB *b = new classB();
func = (classA*) b;
newf = &dynamic_cast<classF &>(*func); // Throws an exception
Upvotes: 3
Reputation: 5370
If you function want a classF
pointer you should pass it a classF
pointer. Your code should not even compile like this because of the function requiring a classF
and you give it a classA
You can get this to compile with casting the class to classF
but you should not do this. This will get you into undefined behavior land because you would basically be lying to your compiler and say "this other class is a classF
pointer", which would not be true.
What you can always safely do it cast to a pointer of the base class (like you do in your example with casting to classA
)
You should also switch from c-style casts to c++ style casts (like static_cast
or dynamic_cast
). This can also help you in your situation. With dynamic cast you can safely cast a class to a derrived class.
Like this:
class A {};
class B : public A {};
class C : public A {};
A* b-obj = new B;
A* c-obj = new C;
now both c-obj
and b-obj
are pointers to A
so we don't know anymore if they are B or C. You can check this with dynamic_cast
C* ptr = dynamic_cast<C*>(b-obj); //returns null because b-obj cannot be converted to C*
C* ptr = dynamic_cast<C*>(c-obj); //does not return null
Your code can look like that then:
func = static_cast<A*>(e); // cast to base class.
//later then.
classF* funcF = dynamic_cast<F*>(func);
if(funcF != NULL)
{
function(func);
}
the c-style casts can have some side effects you may not like. So strongly recommend to familiarize yourself with c++ casts.
Upvotes: 2