让我们看看这段代码:
class CBase
{
public:
virtual vfunc() { cout << "CBase::vfunc()" << endl; }
};
class CChild: public CBase
{
public:
vfunc() { cout << "CChild::vfunc()" << endl; }
};
int main()
{
CBase *pBase = new CBase;
((CChild*)pBase)->vfunc(); // !!! important
delete pBase;
return 0;
}
输出结果为:
CBase::vfunc()
但我想看看:CChild :: vfunc()
显式((CChild *)pBase)转换为“CChild *”类型。那么为什么调用派生的vfunc()我需要用以下代码替换“重要”字符串: ((CChild *)PBASE) - &GT; CChild :: vfunc();
答案 0 :(得分:6)
这不是它的工作原理 - 这是:
CBase *pBase = new CChild;
pBase->vfunc();
virtual
函数调用在指针上动态解析&amp;引用(除非您明确地调用该方法,就像您所做的那样)。这意味着你告诉编译器指针是什么并不重要,它将在vftable中查找方法。在您的情况下,vftable
是CBase
。
答案 1 :(得分:5)
你做不到。 *pBase
是CBase
类型的对象。您不能将其视为CChild
,因为它不是CChild
对象。
使用强制转换为CChild*
获得的指针会导致程序出现未定义的行为。
答案 2 :(得分:2)
其他答案提出重点 - 补充:如果您实际上可能正在处理CChild
(例如,它是作为参数传递的引用),那么您可以使用dynamic_cast
来沮丧。但是,高度依赖dynamic_cast
通常表明你的设计出了问题。
演员表的细节可以在这里找到: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx
所以这个过程需要通过CBase
将CChild
参数转换为dynamic_cast
,如果引用是CChild
且dynamic_cast
成功,那么你可以确保您正在处理CChild
,然后您可以安全地将其用作CChild
。
答案 3 :(得分:1)
这里的问题似乎很简单。 CBase无法神奇升级到CChild!让我重写你的例子并添加一些评论。它应该是自我解释的......
#include <iostream>
class CBase {
public:
virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; }
virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise
};
class CChild: public CBase {
public:
void vfunc() { std::cout << "CChild::vfunc()" << std::endl; }
~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor
};
int main()
{
CBase *ptr1 = new CBase;
CBase *ptr2 = new CChild;
ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!!
ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase
delete ptr1;
delete ptr2;
}
输出:
CBase::vfunc()
CChild::vfunc()
PS:我刚刚意识到我已经晚了大约5年了,但是因为我发现了这方面的教育价值,所以我会发布它!