c++ - C++从派生类中的虚函数调用非虚函数
问题描述
事实上,类似的问题也被问到这里和那里,但答案并不令人满意。代码示例是
class CBase
{
public:
virtual void act1(){cout<<"CBase::act1()! "<<endl; act2();}
void act2() {cout<<"CBase::act2()! "<<endl; act3();}
virtual void act3(){cout<<"CBase::act3()! "<<endl; act4();}
virtual void act4(){cout<<"CBase::act4()! "<<endl; act5();}
void act5() {cout<<"CBase::act5()! "<<endl; }
virtual ~CBase(){}
} ;
class CDerive : public CBase
{
public:
void act3(){cout<<"CDerive::act3()! "<<endl; act4();}
void act4(){cout<<"CDerive::act4()! "<<endl; act5();}
void act5(){cout<<"CDerive::act5()! "<<endl; }
virtual ~CDerive(){}
} ;
int main()
{
CBase *p=new CDerive;
p->act1();
cout<<endl;
p->act5();
delete p;
return 0;
}
输出是
CBase::act1()!
CBase::act2()!
CDerive::act3()!
CDerive::act4()!
CDerive::act5()!
CBase::act5()!
关于p->act1()
- 因为
act1()
是一个虚函数并且派生类没有实现它,所以程序会调用CBase::act1()
; - 然后程序将调用
CBase::act2()
; act3()
是一个虚拟函数,程序会调用CDervie::act3()
;act4()
也是一个虚拟函数,程序会调用CDervie::act4()
;- 看不懂的部分来了,
act5()
不是虚函数,p
是属于的指针CBase
,基本上p
只能访问CBase
!但输出是CDerive::act5()!
相反,我认为p->act5()
会打电话。CBase::act5()
原理——基类指针只能访问基类和虚函数中定义的函数,与真正的输出之间似乎存在矛盾。原因也无法从虚拟表中解释,因为CDerive::act5()
甚至不在虚拟表中。所以,我的问题是
- 这些背后的理由是什么?
- 什么时候
CBase *p=new CDerive
或CDerive a; CBase *p=&a
?
解决方案
我认为这个问题的重点是对this
指针的理解。编译时,真正的功能是(以CDerive::act4()
为例)
void CDerive::act4(CDerive *this)
{
cout<<"CDerive::act4()! "<<endl;
this->act5();
}
所以,this->act5()
等价于CDerive::act5()
,输出为CDerive::act5()!
。
但是等等,这似乎与函数相矛盾CBase::act2()
。按照同样的逻辑,真正的功能应该是
void CBase::act2(CBase *this)
{
cout<<"CBase::act2()! "<<endl;
this->act3();
}
并且this->act3()
会打电话CBase::act3()
,这是不对的!
所以,真正的调用过程是
if func() is not a virtual function
this -> func() = class::func()
else
this -> func() = v_ptr -> v_talbe -> func()
使用上面的两个示例来演示它:
act5()
不是虚函数,所以程序会调用CDerive::act5()
act3()
是一个虚函数,所以程序会调用CDerive::act3()
这样逻辑一致,输出正确。
推荐阅读
- excel - 我们可以像这样改变形状或对象组的边框颜色吗?
- time - 将模拟读数转换为时间范围
- xamarin.forms - Xamarin.Forms:以编程方式设置 Rowspan
- amazon-web-services - 如何降低(开放)Vpn 服务器的带宽成本?
- python - Django:使用名为“id”的 URL 关键字参数调用预期的视图 likeList
- ios - 如何支持相同应用但不同环境的通用链接?
- javascript - 如何添加依赖来响应?
- sql - (SQL) 如何检查一个值是否在另一个表中?
- r - 有没有办法 left_join 两个具有不同日期的序列,以便两者都出现?
- episerver - 将 Episerver 内容作为服务公开给第三方应用程序