理解c++语言的重载、覆盖和隐藏
关于c++语言的重载、覆盖和隐藏的文章很多也很长,但还是基本都没能说到点子上。
本来文章的标题应该叫《c++类层次结构中的屏蔽现象》,但是为了博取眼球,以及搜索引擎优化不得不用上面那个标题,当然了,目的是为了理解c++中的重载、覆盖和隐藏现象。
好了,好了,我要吹牛了,大家快跑啊。等等,csdn搞了markdown这个新玩意,我日,不会用。。。
同一个类
重载发生在同一个类中,比较简单,没什么好说的。
继承,也就是就类层次结构
这个看上去比较复杂了,会出现下列几种情况的组合
参数 | virtual | 现象 |
---|---|---|
参数相同 | 有virtual | 覆盖 |
参数相同 | 无virtual | 隐藏 |
参数不同 | 有virtual | 隐藏 |
参数不同 | 无virtual | 隐藏 |
那么问题来了,覆盖和隐藏是个什么鬼?到底有什么区别?是不是很纠结?是不是一下子就迷茫了?
其实我可以很负责任的告诉你,它们根本没区别。
现在你可以把上面那个表忘掉了。
我发明了一个词,叫屏蔽(shield)。
在继承体系或者类层次结构的派生类中出现了与基类同名的方法时,派生类的方法将会屏蔽已经继承到的基类的方法,不管参数是否相同,也不管是否有virtual关键字。 这是c++编译器强制的,没有商量的。
举例,假设基类B中有一个名字叫f1的方法,派生类D中也有一个名叫f1的方法,那么不管这两个方法是否参数相同,也不管它们是否有virtual关键字,派生类的f1方法将自动屏蔽基类的f1方法。意思就是说我们无法通过派生类D来访问基类B的f1方法了,但是基类B的方法确确实实是已经被派生类继承过来了,可以把这种屏蔽理解为派生类将同名的基类方法访问控制权限设为protected。
那么c++编译器是通过什么途径来达到这种屏蔽效果的呢?有两种方式,具体如下:
1,限制访问
还是上面那个例子,D本来已经继承到了B的f1方法,但是同名同参数的情况下,我们无法通过D来调用到B的f1。比如,
D d;
d.f1();
我们调不到B的f1。
2,编译出错。
你可能会说,那好办啊,参数不一样不就行了。比如B的f1是void f1(),然后D的f1是void f1(int),然后
D d;
d.f1();
这样编译会出错,error C2660: “D::f1”: 函数不接受 0 个参数。
屏蔽似乎起作用了。
那么问题来了,既然D继承到了B的方法,那我们可不可以突破这种屏蔽效果来强撸B的方法呢?答案是可以。用向上强制转换(upcasting)。
B* pB = &D;
注意,这个upcasting对于同参数且都使用virtual关键字的方法会触发多态,触发了多态就意味着我们再也没法调用B的那个被屏蔽的方法了,也就是说B的方法被D永久的屏蔽了。
多态
文章到了这里,如果你能看懂上面的论述,你将会开始怀疑人生,永久屏蔽?wtf…
是的,要的就是永久屏蔽,不然多态从技术上就无法实现
代码
#include <iostream>
using namespace std;
class CBase
{
public:
virtual void f1(){cout<<"B::f1()"<<endl;}
void f2(){cout<<"B::f2()"<<endl;}
virtual void f3(){cout<<"B::f3()"<<endl;}
void f4(){cout<<"B::f4()"<<endl;}
};
class CDerive : public CBase
{
public:
virtual void f1(){cout<<"D::f1()"<<",";CBase::f1();} //参数相同,有virtual------覆盖
void f2(){cout<<"D::f2()"<<",";CBase::f2();} //参数相同,无virtual------隐藏
virtual void f3(int){cout<<"D::f2()"<<",";CBase::f3();} //参数不同,有virtual------隐藏
void f4(int a){cout<<"D::f4(int)"<<",";CBase::f4();} //参数不同,无virtual------隐藏
};
int main()
{
//正常访问
CDerive d;
d.f1();
d.f2();
d.f3(1);//d.f3();编译报错,error C2660: “CDerive::f3”: 函数不接受 0 个参数
d.f4(1);//d.f4();编译报错,error C2660: “CDerive::f4”: 函数不接受 0 个参数
cout<<endl;
//强制访问
CBase* pB = &d;
pB->f1();
pB->f2();
pB->f3();
pB->f4();
getchar();
return 0;
}