Reputation: 2074
Suppose I have a pair of base classes:
class A
{};
class B
{
virtual void foo(A* ref);
virtual void foo2(A* ref);
};
And from them, a few derived classes:
class C : virtual public A
{
int data;
};
class D : public B
{
virtual void foo(A* ref)
{
((C*) (ref)).data = 5;
}
};
class E : virtual public A
{
int otherData;
};
class F : public B
{
virtual void foo2(A* ref)
{
((E*) (ref)).otherData = 6;
}
};
And finally, we have a class that follows suit, as such:
class G : public E, public C
{
};
with a main function that goes as follows:
int main()
{
B* myD = new D();
B* myF = new F();
A* myA = new G();
myD->foo(myA);
myF->foo2(myA);
return 0;
}
Ok, IGNORING the obvious fact that this is a 'dreaded diamond' (which, the "multiple As" problem has been averted due to virtual
), the general idea is that I want to have all my objects be Gs, Ds and Fs, but stored as references to As and Bs. I want to be able to use B's (which is actually always either D or F) virtual functions to modify the values of G... However, A and B do not know of any of their child classes, and thus cannot be declared using them. This means that the virtual function arguments must always be a pointer to an A. However, D wants to have it's input always be a C, and F wants it's input to be an E. While this might not have been an issue if G was inheriting from only one parent, our current G is inheriting from 2 parents; I do not know how the this
pointers actually work in the underlying context of situations like this... however, I do not feel like this is going to be a possible situation.
Would anyone be willing to shed some light on the mechanisms of casting pointers to parent/child classes, and if there would be any way this could be pulled off?
Upvotes: 0
Views: 425
Reputation: 70492
As Kerrek and Andrew say, you should use dynamic_cast
. However, if the children of A
are static, you could use a different trick, which might be faster than dynamic_cast
(since it doesn't depend on RTTI, see this question for more information).
class C;
class D;
class E;
class F;
class A
{
public:
virtual C * isC () { return 0; }
virtual E * isE () { return 0; }
};
class C : virtual public A
{
friend class D;
int data;
C * isC () { return this; }
};
class E : virtual public A
{
friend class F;
int otherData;
E * isE () { return this; }
};
Now, D
and F
can query A
to see if isC
or isE
returns a valid pointer.
Upvotes: 0
Reputation: 477512
Since A
is a virtual base of G
, you cannot convert a pointer to A
to a pointer to G
statically. The whole meaning of virtual
is "determined at runtime", and so the nature of the A
-subobject to which you have a pointer can only be known at runtime. For example, in your case consider:
A * p = new G, q = new C;
Now both p
and q
point to some A
-subobject, but the nature of the most-derived object in which they are contained is only determined by the actual most derived type. Thus it is impossible to have one single, fixed conversion rule from A*
to G*
or from A*
to C*
.
The only way to perform the cast is dynamically, i.e. via dynamic_cast<C*>(p)
etc.
(By contrast, in non-virtual inheritance it is always known how a subobject relates to its more-derived objects, and thus pointers can be converted statically. There may be issues of naming ambiguity if you have multiple repeated bases, but there's no issue with locating the base subobjects.)
Upvotes: 1
Reputation: 68728
Assuming you have RTTI switched on, which you most likely do, you can use dynamic_cast to attempt to up-cast a base class pointer to a derived (or sibling) class pointer. The referenced object is tested at runtime to see if it is a compatible class, if this is not a valid upcast than it will return 0, in which case you can test for that and branch.
http://en.wikipedia.org/wiki/Dynamic_cast
Upvotes: 1