首页
登录 | 注册

C++父类与子类关系以及函数重载、覆盖和隐藏规则

今天去HTC面试,笔试考了逻辑、c语言、c++语言几个部分,C/C++考的全是基本语法,没有考算法。C语言部分做的还不错,C++部分却做的那么多不确定,其中大部分是C++父子类之间关系以及函数重载、覆盖以及隐藏规则。
在C++语言中,虚函数是非常重要的概念,虚函数是实现C++面向对象中多态性和继承性的基石。而多态性和继承性则是面向对象语言的精髓。掌握虚函数才算是真正掌握C++语言,而C++语言中虚函数的继承覆盖与函数重载有些类似,很多初学者搞不清他们之间的关系。
首先要明确覆盖(override)与重载(overload)的定义,区别出什么是覆盖和重载:
覆盖就是派生类中虚成员函数覆盖基类中同名且参数相同的成员函数。
如下例:

[cpp] view plaincopy
  1. class CBase  
  2. {  
  3. public:  
  4.     CBase();  
  5.     virtual void Walk(){cout<<"CBase:Walk"<
  6.     virtual void Jump(){cout<<"CBase:Jump"<
  7. };  
  8. class CDerivedA : public CBase  
  9. {  
  10. public:  
  11.     CDerivedA();  
  12.     void Walk(){cout<<"CDerivedA:Walk"<
  13.     void Jump(){cout<<"CDerivedA:Jump"<
  14. };  
  15. int main()  
  16. {  
  17.     CBase *pTmp1=new CDerivedA ;  
  18.     pTmp1->Walk();  
  19.   
  20.     return 0;  
  21. }  



上例中,CDerived和CBase之间就是函数覆盖关系,Walk和Jump函数被派生类覆盖,输出肯定是派生类函数的输出。下面就这几者关系着重学习。再看看下例:

[cpp] view plaincopy
  1. class CBase  
  2. {  
  3. public:  
  4.     CBase();  
  5.     virtual void Walk(){cout<<"CBase:Walk"<
  6.     virtual void Jump(){cout<<"CBase:Jump"<
  7.     void Run(int speed){cout<<"CBase:Run:"<<"Speed="<
  8. };  
  9. class CDerivedA : public CBase  
  10. {  
  11. public:  
  12.     CDerivedA();  
  13.     void Walk(){cout<<"CDerivedA:Walk"<
  14.     void Jump(){cout<<"CDerivedA:Jump"<
  15.     void Run(int speed) {cout<<"CDerivedA:Run"<<"Speed="<
  16. };  
  17. int main()  
  18. {  
  19.     CBase *pTmp1=new CDerivedA ;  
  20.     pTmp1->Walk();  
  21.     pTmp1->Run(20);  
  22.     return 0;  
  23. }  
这里基类中Run与派生类中Run函数就是重载(overload)关系,当使用基类来调用派生类对象中重载函数,会根据其作用域来判断,如基类CBase,其作用域就是CBase这个类的大括号包含的内容,派生类CDeriverdA其作用域就是CDerivedA大括号中包含的内容。因此在使用基类调用派生类对象中的Run方法时,会执行基类的Run方法。
关于作用域可见性规则(摘于网上:http://www.51laifu.cn/archives/2012/610/article-31092.html)如下:


 如果存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,那么外层标识符在内层依然可见,如果在内层声明了同名标识符,则外层标识符在内层不可见,这时称内层标识符隐藏了外层同名标识符,这种现象称为隐藏规则。

    在类的派生层次结构中,基类的成员和派生类新增的成员都具有类作用域。二者的作用范围不同,是相互包含的两个层,派生类在内层。这时,如果派生类声明了一个和某个基类成员同名的新成员,派生的新成员就隐藏了外层同名成员,直接使用成员名只能访问到派生类的成员。如果派生类中声明了与基类同名的新函数,即使函数的参数表不同,从基类继承的同名函数的所有重载形式也都被隐藏。如果要访问被隐藏的成员,就需要使用类作用域分辨符和基类名来限定。

根据上面的解释,CBase类处于作用域的外层,因此派生类的方法对于其将是不可见的,即隐藏的。而在派生类中,如果有重载函数时,基类函数将会被隐藏,否则基类函数就不被隐藏。


函数重载和虚函数都能实现对象的多态特性,但是函数重载只能实现静态的多态,也就是在编译时多态,即编译器会给重载的函数在编译时加上不同的前缀,是函数名在运行时不同。而虚函数可以实现动态多态,即运行时多态,但是虚函数实现需要增加额外的虚函数指针等,会增加相应空间。
再看下例:

[cpp] view plaincopy
  1. class CBase  
  2. {  
  3. public:  
  4.     CBase();  
  5.     virtual void Walk(){cout<<"CBase:Walk"<
  6.     virtual void Jump(){cout<<"CBase:Jump"<
  7.     void Run(int speed){cout<<"CBase:Run:"<<"Speed="<
  8. };  
  9. class CDerivedA : public CBase  
  10. {  
  11. public:  
  12.     CDerivedA();  
  13.     void Walk(){cout<<"CDerivedA:Walk"<
  14.     void Jump(){cout<<"CDerivedA:Jump"<
  15.     void Run(int speed) {cout<<"CDerivedA:Run"<<"Speed="<
  16.     void Run(int speed,int direction){cout<<"CDerivedA:Run"<<"Speed="<";Direction="<
  17. };  
  18. int main()  
  19. {  
  20.     CBase *pTmp1=new CDerivedA ;  
  21.     pTmp1->Walk();  
  22.     pTmp1->Run(20);  
  23.     CDerivedA *pTmp2=(CDerivedA*)pTmp1 ;  
  24.     pTmp2->Run(20,3);//合法的  
  25.     //pTmp1->Run(20,3);//不合法  
  26.     return 0;  
  27. }  
以上代码就可以看出,派生类中的重载方法,在基类是不能调用的,编译的时候就会出错。

C++中实现多态的三种方式:
模板、函数重载、虚函数。


[cpp] view plaincopy

相关文章

  • java编程中的异常分析及面向对象的思考总结[图]
    java编程中的异常分析及面向对象的思考总结[图] 1.异常: 程序中出现的不正常现象. 2.异常的由来: 程序在运行的过程中出现了不正常的情况,程序把它看成对象提取了属性行为(名字,原因,位置等信息) 形成了各种异常类 3.异常的分类:( ...
  • RESTful API 调用很多人都在用 Retrofit,说到 Retrofit 就不得不提动态代理,虽然这不是它唯一的亮点,而且也不是动态代理的典型使用场景,但大家就是爱问:说说动态代理是怎么回事吧?Retrofit 的解析请见 拆轮子 ...
  • Java基础1:深入理解Java面向对象三大特性
    这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔讲点Docker.ELK,同时也分享技术干货和学习经验,致力于Ja ...
  • Java基础10:全面解读Java异常
    这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM.SpringBoot.MySQL.分布式.中间件.集群.Linux.网络.多线程,偶尔讲点Docker.ELK,同时也分享技术干货和学习经验,致力于Ja ...
  • 每个程序都不可避免地要进行异常处理,爬虫也不例外,假如不进行异常处理,可能导致爬虫程序直接崩掉.以下是网络爬虫出现的异常种类. URLError 通常,URLError在没有网络连接(没有路由到特定服务器),或者服务器不存在的情况下产生. ...
  • 一.String与Date(java.util.Date)互转 1.1 String -> Date Java代码 String dateStr = "2010/05/04 12:34:23";           ...

2019 unjeep.com webmaster#unjeep.com
12 q. 0.025 s.
京ICP备10005923号