假设我有一对基类:
class A
{};
class B
{
virtual void foo(A* ref);
virtual void foo2(A* ref);
};
从他们那里得到一些派生类:
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;
}
};
最后,我们有一个适合的课程:
class G : public E, public C
{
};
主要功能如下:
int main()
{
B* myD = new D();
B* myF = new F();
A* myA = new G();
myD->foo(myA);
myF->foo2(myA);
return 0;
}
好的,忽略一个显而易见的事实,即这是一个'可怕的钻石'(由于virtual
而避免了“多重As”问题),一般的想法是我想要拥有所有的物体是Gs,Ds和Fs,但存储为As和Bs的引用。我希望能够使用B(实际上总是D或F)虚拟函数来修改G的值...但是,A和B不知道他们的任何子类,因此无法使用他们。这意味着虚函数参数必须始终是指向A的指针。但是,D希望它的输入始终是C,而F希望它的输入是E.虽然这可能不是问题,如果G是继承自一个父母,我们现在的G继承自2个父母;我不知道this
指针在这种情况的基础上下文中是如何实际工作的......但是,我觉得这不会是一种可能的情况。
是否有人愿意阐明将指针转换为父/子类的机制,如果有任何方法可以将其删除?
答案 0 :(得分:1)
假设您已经打开了RTTI,您很可能会这样做,您可以使用 dynamic_cast 来尝试向基类指针上传一个派生(或同级)类指针。引用的对象在运行时进行测试,以查看它是否是兼容类,如果这不是有效的upcast而不是返回0,在这种情况下,您可以测试该分支。
答案 1 :(得分:1)
由于A
是G
的虚拟基础,因此您无法将指向A
的指针静态转换为指向G
的指针。 virtual
的全部含义是“在运行时确定的”,因此只有在运行时才能知道具有指针的A
- 子对象的性质。例如,在您的情况下考虑:
A * p = new G, q = new C;
现在,p
和q
都指向某些 A
- 子对象,但是包含它们的派生程度最高的对象的性质仅为由实际最衍生的类型决定。因此,从A*
到G*
或从A*
到C*
都不可能有一个固定的转换规则。
执行演员表的唯一方法是动态,即通过dynamic_cast<C*>(p)
等。
(相比之下,在非虚拟继承中,总是知道子对象如何与其更多派生对象相关,因此指针可以静态转换。可能存在命名歧义的问题,如果你有多个重复的基础,但找到基础子对象没有问题。)
答案 2 :(得分:0)
正如Kerrek和Andrew所说,你应该使用dynamic_cast
。但是,如果A
的子项是静态的,则可以使用不同的技巧,这可能比dynamic_cast
更快(因为它不依赖于RTTI,请参阅this question以获取更多信息)。
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; }
};
现在,D
和F
可以查询A
以查看isC
或isE
是否返回有效指针。