Multi-inheritance Polymorphism
Suppose my code is setup like this:
Code:
class A
{
};
class B
{
};
class C : A,B
{
};
A* someFunction()
{
return (A*) new C;
}
Notice I've casted a C into an A. C inherits A, but also B. Is this safe to do if I still know what type it is and cast it back latter, or does multi-inheritance bring up problems with polymorphism? As a second part to my question, would it also be okay to cast from C to B? In other words, does their order in the inheritance area of C's class definition matter, or can you only revert to the first inherited class? Thanks in advance.
Re: Multi-inheritance Polymorphism
This type of casting called upcasting is always safe.
An object of C can be cast to either A or B.
You should however use dynamic_cast 'cause it will check if the casting is valid.
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by
Etherous
In other words, does their order in the inheritance area of C's class definition matter, or can you only revert to the first inherited class? Thanks in advance.
Hello Etherous,
that's a very good question (something I want to learn more)
AFAIK,
in a single hierarchical..did I spell that right? multiple inheritance,
the placement of the list of the base classes and in order which they
appear in the constructor list doesn't really matter.
But,
if it's more than one level,
the order of constructing happens from the top most base class and to the horizontonal classes.
so if A is at the top, B derives from A. C is at the same level as B, and D derives from B and C,
the order of construction is A, B, C, D, and vice versa for the destructors.
I fear that this could present a problem, along with the ambiguty issues.
As for the "upcasting"
you just can't get around slicing (can we?)
this led me to believe at this point in my learning that
if casting is needed in an inheritance,
the chance is that there exists an alternative design where you could use compostion.
To test this, I went over my old programming excercises and tried composition modeling,
and viola! it worked great.
hope this helps :)
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by Etherous
Notice I've casted a C into an A.
Actually, assuming that the example was changed such that public inheritance was used, an explicit cast would be unnecessary, since C is-a A:
Code:
class A
{
public:
virtual ~A() {}
};
class B
{
public:
virtual ~B() {}
};
class C : public A, public B
{
};
A* someFunction()
{
return new C;
}
Quote:
Originally Posted by Etherous
As a second part to my question, would it also be okay to cast from C to B?
Yes, but again a C is-a B, so an explicit cast is unnecessary. (If you really did want to explicitly cast, static_cast will suffice.)
Quote:
Originally Posted by _Superman_
You should however use dynamic_cast 'cause it will check if the casting is valid.
Yes, to cast from A* to the B*, or from A* to C*, or from B* to C* (though static_cast can be used for the latter two if we know for certain that the object pointed to is a C).
Quote:
Originally Posted by potatoCode
As for the "upcasting"
you just can't get around slicing (can we?)
Slicing does not happen here since the return type is a pointer.
Re: Multi-inheritance Polymorphism
Wow. Thanks so much for all your replies. This really helps.
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by
laserlight
Slicing does not happen here since the return type is a pointer.
Hello laserlight, how are you buddy?
You always bring out the best in me!!
My understanding of the return (A*) new C; was that object C was first allocated then casted to A* which could only hold(allocated memory) the un-sliced part of C which is A. That tells me A was constructued "from" C, although A was not copy constructed from C which in turn makes me question myself...
But I guess I had it all wrong including the new part.
can you explain this a bit more and point out what I got it wrong?
Thanks
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by potatoCode
My understanding of the return (A*) new C; was that object C was first allocated then casted to A* which could only hold(allocated memory) the un-sliced part of C which is A.
Let's simplify the example:
Code:
#include <iostream>
class A
{
public:
virtual void foo() const
{
std::cout << "A::foo" << std::endl;
}
virtual ~A() {}
};
class C : public A
{
public:
virtual void foo() const
{
std::cout << "C::foo" << std::endl;
}
};
A* someFunction()
{
return (A*)new C;
}
int main()
{
A* p = someFunction();
p->foo();
delete p;
}
If you are right, and the explicit C-style cast to A* sliced off the C part of the object, then we would expect the output to be A::foo. However, this is not the case, since the A pointer continues to point to the C object, so the virtual call causes C's version of foo() to be called. Let's take a look at an example where slicing occurs:
Code:
#include <iostream>
class A
{
public:
virtual void foo() const
{
std::cout << "A::foo" << std::endl;
}
virtual ~A() {}
};
class C : public A
{
public:
virtual void foo() const
{
std::cout << "C::foo" << std::endl;
}
};
A someFunction()
{
return C();
}
int main()
{
A x = someFunction();
x.foo();
}
Here, someFunction() returns an A object, not an A pointer, so slicing occurs and there is no polymorphism as in the first example.
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by
laserlight
(If you really did want to explicitly cast, static_cast will suffice.)
No, static_cast won't suffice.
An upcast is always type-safe. If you don't upcast explicitly the compiler will check that it's a valid upcast for you.
But if you do upcast explicitly you shortcut the compiler's type checking and assume full responsibility for the cast yourself. And this includes that it works a runtime which requires you to put in a dynamic_cast.
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by _uj
No, static_cast won't suffice.
It will, if you "if you really did want to explicitly cast". My point is that if you know for certain that a downcast will succeed, then you can use static_cast, and thus it follows that since an upcast will always succeed, then if you are anal about an explicit cast even when it is of no use (or as you pointed out, when it can even be harmful), static_cast should be good enough for you.
Re: Multi-inheritance Polymorphism
Thanks laserlight, you are, once again, of course right!
I did some testing on my own and found out that you are also right
in saying that static cast will suffice.
And I didn't know about the no need to explicitly cast
because of an IS-A relationship either (why couldn't I imgaine it before!)
few more question.
Code:
int main()
{
A* p = someFunction();
p->foo();
A* p2(0);
C* ptr = static_cast<C*>(p2);
ptr->hi(); // hi() is a simple method in C only
delete p;
}
ptr in this code does call the hi() method in C,
which for the sake of my sanity, shouldn't happen.
I assume, this is only UB, correct?
Q2. When I generally debug (gdb), I mostly watch variables, funtion arguments and
keep my eyes on the address. Is this the right or nomral way of debugging?
Q3. When do I need to watch CPU register and callstack?
as always, thanks!
Re: Multi-inheritance Polymorphism
Quote:
Originally Posted by potatoCode
ptr in this code does call the hi() method in C,
which for the sake of my sanity, shouldn't happen.
I assume, this is only UB, correct?
Yes, since you are dereferencing a null pointer. It probably "works" because hi() say, does not access any of the member variables.