关闭

C++ 同名隐藏、覆盖,虚函数 的详解和对比

593人阅读 评论(0) 收藏 举报
分类:
不同作用域声明的标识符的可见性原则:

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

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

    作用域分辨符,就是"::",它可以用来限定要访问的成员所在的类的名称。一般的使用形式是:

    类名::成员名

    类名::成员名(参数表)

    关于同名隐藏的验证:

代码1:

  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5.     public:  
  6.   
  7.   
  8.     void print2(){  
  9.         cout<<"A print2 !"<<endl;  
  10.     }  
  11. };  
  12.   
  13.   
  14. class B:public A  
  15. {  
  16.       
  17.     public:  
  18.   
  19.   
  20.     void print2(int x){  
  21.         cout<<"B print2 !"<<x<<endl;  
  22.     }  
  23. };  
  24.   
  25.   
  26. int main(){  
  27.     B b;  
  28.     b.print2();  
  29.     return 0;  
  30. }  

    由结果可知已经不能直接从B的对象中直接用函数名访问print2()了。

    将b.print2();  改为: b.A::print2();


    可见能利用域分辨符来定位继承自A被隐藏的print2()函数。

    除了利用域分辨符定位继承自基类并被派生类隐藏的成员以外,还可以利用using关键字加以说明。

    using的一般功能是将一个作用域中的名字引入到另一个作用域中,它还有一个非常有用的用法:将using用于基类中的函数名,这样派生类中如果定义同名但参数不同的函数,基类的函数将不会被隐藏,两个重载的函数将会并存在派生类的作用域中。

代码2:

  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5.     public:  
  6.   
  7.     void print2(){  
  8.         cout<<"A print2 !"<<endl;  
  9.     }  
  10. };  
  11.   
  12. class B:public A  
  13. {  
  14.       
  15.     public:  
  16.     using A::print2;  
  17.     void print2(int x){  
  18.         cout<<"B print2 !"<<x<<endl;  
  19.     }  
  20. };  
  21.   
  22. int main(){  
  23.     B b;  
  24.     b.print2();  
  25.     return 0;  
  26. }  
编译运行:



虚函数与运行时多态:

代码3:

  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5.     public:  
  6.   
  7.     void print(){  
  8.         cout<<"A print !"<<endl;  
  9.     }  
  10. };  
  11.   
  12. class B:public A  
  13. {  
  14.       
  15.     public:  
  16.     void print(){  
  17.         cout<<"B print !"<<endl;  
  18.     }  
  19. };  
  20.   
  21. int main(){  
  22.     A *a=new B();  
  23.     a->print();  
  24.     return 0;  
  25. }  


    类型兼容规则:在需要基类的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。

    类型兼容规则中所指的替代包括以下的情况:

    派生类的对象可以隐含转换为基类对象。

    派生类的对象可以初始化基类的引用。

    派生类的指针可以隐含转换为基类的指针。

    在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。

    代码3中的new B()返回一个指向B对象的指针,之后隐式转换为指向A的指针a,因为a是指向A类对象的指针,因此可以用a来访问继承自A的类B的对象,但是a只能使用继承自A的成员。

    根据赋值兼容规则,可以使用派生类的对象替代基类对象。如果用基类类型的指针指向派生类对象,就可以通过这个指针来访问对象,问题是访问到的只是从基类继承来的同名成员。解决这一问题的方法是:如果需要通过基类的指针指向派生类的对象,并访问某个与基类同名的成员,那么首先在基类中将这个同名函数说明为虚函数。这样,通过基类类型的指针,就可以使属于不同派生类的不同对象产生不同的行为,从而实现运行过程的多态。

    将代码3稍作修改:

    代码4:

  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5.     public:  
  6.   
  7.     virtual void print(){  
  8.         cout<<"A print !"<<endl;  
  9.     }  
  10. };  
  11.   
  12. class B:public A  
  13. {  
  14.       
  15.     public:  
  16.     void print(){  
  17.         cout<<"B print !"<<endl;  
  18.     }  
  19. };  
  20.   
  21. int main(){  
  22.     A *a=new B();  
  23.     a->print();  
  24.     return 0;  
  25. }  


    

1
0
查看评论

c++继承中的函数覆盖规则

问题:如果如图的继承方式,类B会不会自己复制一个和类A一模一样的test函数呢?   测试数据:   #include usingnamespace std; class A { public: void test(){ static ...
  • u013009575
  • u013009575
  • 2014-02-12 09:47
  • 1110

C++成员函数的重载、覆盖与隐藏详解

成员函数的重载、覆盖与隐藏成员函数的重载、覆盖(override)与隐藏很容易混淆,C++程序员必须要搞清楚概念,否则错误将防不胜防。在看《高质量c/c++》中看到了函数的隐藏和覆盖是这么说的:覆盖的是指子类函数覆盖基类函数 在不同的类内(分别位于子类和父类)。 同名同参。 基类的函数名前必须...
  • gatieme
  • gatieme
  • 2016-03-15 21:13
  • 1251

C++ 子类函数对父类同名函数的覆盖

class B { public:     void f(int) const     {         cout     }    &...
  • dxy408460910
  • dxy408460910
  • 2013-07-23 09:58
  • 2060

C++继承:同名隐藏、覆盖,虚函数

不同作用域声明的标识符的可见性原则:     如果存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,那么外层标识符在内层依然可见,如果在内层声明了同名标识符,则外层标识符在内层不可见,这时称内层标识符隐藏了外层同名标识符,这种现象称为隐藏规...
  • tobacco5648
  • tobacco5648
  • 2012-06-10 16:12
  • 25678

C++重载覆盖和隐藏,虚函数与纯虚函数

这几个概念都有一个共同点:函数名称相同,所以不免让人混淆,大致的区别如下: 重载(overload): 必须在一个域中,函数名称相同但是函数参数不同,重载的作用就是同一个函数有不同的行为,因此不是在一个域中的函数是无法构成重载的,这个是重载的重要特征 覆盖(override): 覆盖指的是派生类...
  • white0blue
  • white0blue
  • 2015-07-03 21:04
  • 904

windows同名文件覆盖提示(c++实现)

文件操作可以说在开发过程中经常用到,我们平时一般都是对文件的读写操作,但是实际上文件的拷贝、移动、删除、重命名等也很重要,那文件拷贝、移动到目标路径时,若同一路径下存在同名文件,该怎么让windows弹出“复制或替换”、“不要复制”、“复制,但保留这两个文件”如下类似提示框呢? 这就需要用...
  • laozuodong
  • laozuodong
  • 2017-06-22 17:57
  • 219

C++覆盖(虚函数的实现原理)

Class Shape { public: virtual void cal_area() { } private: int m_ir; };Class Circle:public Shape { public: virtual void cal_area()...
  • qq_23225317
  • qq_23225317
  • 2016-10-14 22:13
  • 242

C++ 虚函数;重载与覆盖;虚继承

1.什么是虚函数 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略。
  • miao65272156
  • miao65272156
  • 2014-05-08 16:24
  • 1879

C++中函数覆盖和使用虚函数有什么区别

举个例子 class fruit { public:     void func()     {         printf("fruit\n");...
  • fron_csl
  • fron_csl
  • 2016-03-09 09:41
  • 1097

C++基类,派生类,同名覆盖原则

// 同名覆盖原则.cpp: 主项目文件。#include "stdafx.h"#include#includeusing namespace std;class One{private: string name; int age;public: virtual ~One( )=...
  • Free_Program_1314
  • Free_Program_1314
  • 2011-06-16 13:50
  • 5959
    个人资料
    • 访问:11917次
    • 积分:462
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:3篇
    • 译文:0篇
    • 评论:6条
    最新评论