我有3个班级
class A {
//...
}
class B : public A {
//...
}
C班:
#include "A.h"
#include "B.h"
class C
{
void method(A anObjOfA);
void method(B anObjOfB);
}
现在,如果我这样做
B* ptr = new B();
A* ptrToB = ptr;
c.method(*ptrToB);
它调用A类型的对象的方法,而不是继承的实际类型B ..我怎样才能确保调用inheritence-tree中最深的对象的正确函数,而不是在编译时实际知道它的类型?
PS:我确定这是一个noob问题,对于我的生活,我在这里找不到任何结果,因为每个人都在忙着理解“虚拟”关键字,这对我来说非常清楚,但是这不是问题。答案 0 :(得分:5)
因为解析函数重载是在编译时完成的。当你调用函数时,它只能看到指针的A
部分,即使它可以指向B。
也许您想要的是以下内容:
class A
{
public:
virtual void DoWorkInC()
{
cout << "A's work";
}
virtual ~A() {}
};
class B : public A
{
public:
virtual void DoWorkInC()
{
cout << "B's work";
}
};
class C
{
void method(A& a)
{
a.DoWorkInC();
}
}
答案 1 :(得分:0)
让你的A,B类在其respectivbe类中实现虚函数:
class A {
//...
public:
virtual void doTask();
};
class B : public A {
//...
public:
void doTask();
};
Ket A :: doTask()和B :: doTask()以对象特定的方式执行各自的任务,即A :: doTask()执行具有对象集可见性的任务,并且B :: doTask()用于将对象集的可见性设置为B对象。 现在,让这个电话是这样的:
B* ptr = new B();
A* ptrToB = ptr;
c.method(ptrToB); // pointer is passed
在C :: method(A * ptr)中,它可能类似于:
void C::method(A * ptr) {
ptr->doTask(); this would actuall call A::doTask() or B::doTask() as dynamically binded
}
答案 2 :(得分:0)
编译器不够聪明,无法猜出你想要调用哪种方法。在您的情况相同的情况下,您可能实际上想要调用第一个版本,因为您使用的是A*
。这让程序员继续工作:具体。如果您不想使用ptr
(根据需要调用第二个版本),则需要专门投射它:
c.method(*((B*)ptrToB));
使用动态演员或更好:
c.method(*dynamic_cast<B*>(ptrToB));
这可能是不安全的,因为你是“向下转发”,在这种情况下,动态强制转换可能会抛出异常并且C样式强制转换不会但会导致内存泄漏。你必须非常小心。
答案 3 :(得分:0)
感谢@texasbruce我找到了答案,RTTI
代码如下所示:
A* someAOrBPtr = ...
...
B* testBPtr = dynamic_cast<B*>(someAOrBPtr);
if( testBPtr ){
// our suspicions are confirmed -- it really was a B
C->method(testBPtr);
}else{
// our suspicions were incorrect -- it is definitely not a B.
// The someAOrBPtr points to an instance of some other child class of the base A.
C->method(someAOrBPtr);
};
编辑:事实上,我可能会在C-&gt;方法中进行动态转换,因此只有一个
C :: method(A * ptrOfBase)
然后在C的一个'方法'中做适当的事情(取入或取出C的各个容器成员变量)。