steiryx
steiryx

Reputation: 81

C++ casting to an object class using inherited parent class

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

Answers (2)

Shachar Shemesh
Shachar Shemesh

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

Hayt
Hayt

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-objare 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

Related Questions