C++中的重载、覆盖、隐藏
前几天面试时被问及C++中的覆盖、隐藏,概念基本答不上来,只答了怎么用指针实现多态,也还有遗漏。最终不欢而散。回来后在网上查找学习了一番,做了这个总结。其中部分文字借用了别人的博客,望不要见怪。引用的博客如下:
http://www.cnblogs.com/feiguo/archive/2013/11/29/3449352.html
- 概念
一、重载(overload)
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个作用域中) ;
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
(5)返回值可以不同;
二、重写(也称为覆盖 override)
是指派生类重新定义基类的虚函数,特征是:
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有 virtual 关键字,不能有 static 。
(5)返回值相同(或是协变),否则报错;<—-协变这个概念我也是第一次才知道…
(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的
三、重定义(也成隐藏)
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)返回值可以不同;
(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。
- 例子
#include <iostream> using namespace std; class SParent
{
public:
SParent( ){}; SParent( const SParent &p )
{
cout << "parent copy construct" << endl;
} int add( int a,int b )
{
cout << "parent int add" << endl;
return a + b;
} double add( double a,double b )
{
cout << "parent double add" << endl;
return a + b;
} virtual int dec( int a,int b )
{
cout << "parent int dec" << endl;
return a - b;
}
}; class SChild : public SParent
{
public:
//using SParent::add;
float add( float a,float b )
{
cout << "child float add" << endl;
return a + b;
} int dec(int a, int b)
{
cout << "child int dec" << endl;
return a - b;
}
}; int main()
{
/* 测试重载 */
SParent parent;
parent.add( , );
parent.add( (double),(double) );
cout << endl; /* 测试覆盖 */
SChild *pchild = (SChild *)new SParent();/* 基类强转为子类...危险...,用dynamic_cast转换也不行 */
pchild->dec( , ); SParent *pparent = new SChild();
pparent->dec( , );
cout << endl; /* 测试隐藏 */
SChild child;
child.add( (int),(int) ); cout << endl; /* 测试函数表 */
((SParent *)NULL)->add( , );
((SChild *)NULL)->add( , );
int a = ;
((SChild *)&a)->add( , ); cout << endl; /* 测试函数地址 */
((SParent)child).add( (int),(int) );
child.SParent::add( , ); return ;
}
输出结果:
parent int add
parent double add parent int dec
child int dec child float add parent int add
child float add
child float add parent copy construct
parent int add
parent int add
按 <RETURN> 来关闭窗口...
- 理解
int SParent::add(int a,int b)与double SParent::add( double a,double b )是重载
int SParent::add(int a,int b)与double SParent::add( double a,double b )都被子类SChild中的float SChild::add( float a,float b )隐藏
int SParent::dec( int a,int b )被子类SChild中的int SChild::dec( int a,int b )覆盖
- 测试
1.重载测试,简单易懂,略过。
2.覆盖测试。dec函数在基类、子类中同名同参,为虚函数,故称覆盖。
SChild *pchild = (SChild *)new SParent()创建的是一个基类对象,其函数表应该为
SParent *pparent = new SChild();创建一个子类对象,其函数表应该为
由上面的函数表可见,当发生覆盖时,子类的函数名会把基类的同名函数覆盖(这也就是为什么叫覆盖的原因吧)。这样我们可以利用一个指向子类的基类指针实现多态。但重点只有一
个,就是函数表里到底指向谁(不管这个指针经过转换后是什么类型的).故输出分别为父类、子类。这是一个运行时多态。
3.隐藏测试
int SParent::add(int a,int b)与double SParent::add( double a,double b )都被子类SChild中的float SChild::add( float a,float b )覆盖,是因为他们同名,而且在不同的作用域中(基类、子类作用域是不同的)。child.add( (int)3,(int)5 );这行代码中,编译器在子类中查找add函数,只找到了一个(基类的add(int a,int b)会被编译根据隐藏规则略过),再根据隐式类型转换发现该函数适用。如果无法隐式转换,则编译不过。隐藏的原因:防止隐式类型转换造成错误。比如int也是可以转换成char的,假如基类有一函数add(char a,char b),子类也有一函数add(double a,double b)。程序员想着在子类隐式把int转换为double,但编译器可能调的是基类的。这也防止了一些库或封装好的基类对程序员造成困扰。
像上面的代码,如果你确实需要基类的函数,可以用using SParent:add。则把基类的add函数域扩大到了子类,构成重载。
4.函数表测试
上面我们说到函数表,这个是在编译时定好的,程序运行时加载到内存中。这意味着我们可以直接通过地址去调用函数。所以((SChild *)NULL)->add( 4,6 );这种代码也是能运行通过的。网上还有人通过计算直接取到了函数表的地址直接调用了。但这种代码不安全不规范不说,还有个更大的问题。当成员函数里需要调用成员变量时,通过这种假的对象指针肯定找不到成员变量表,直接访问了非法内存。
5.函数地址测试
有了隐藏、覆盖,哪么我们要怎么调用被隐藏、覆盖的函数呢。下面有两种方法:
((SParent)child).add( (int)4,(int)8 );
child.SParent::add( 3,5 );
第一种是比较低效的方法。事实上它是通过拷贝构造函数生成一个临时的基类变量去调用基类的add函数。
第二种通过::指定域去访问。这种方法是编译器根据域直接找到了基类的函数地址,跟函数表没有多大关系。
C++中的重载、覆盖、隐藏的更多相关文章
- C++重载覆盖隐藏
写一个程序,各写出重载覆盖 1 // // main.cpp // 2013-7-17作业2 // // Created by 丁小未 on 13-7-17. // Copyright (c) 201 ...
- C++中的重载隐藏覆盖&&JAVA中的重载覆盖&&多态
class 类继承默认是private, struct 默认继承是public C++中的隐藏: 只要派生类中出现和基类一样的函数名,基类中的函数就会被派生类中的函数给隐藏(如果派生类和基类中的函数名 ...
- C++中的重载,隐藏,覆盖,虚函数,多态浅析
直到今日,才发现自己对重载的认识长时间以来都是错误的.幸亏现在得以纠正,真的是恐怖万分,雷人至极.一直以来,我认为重载可以发生在基类和派生类之间,例如: class A { public: void ...
- c++中 重载 覆盖 隐藏的区别 附加 mutable笔记
成员函数被重载的特征有: 1) 相同的范围(在同一个类中): //2) 函数名字相同: 3) 参数不同: 4) virtual关键字可有可无. 覆盖的特征有: 1) 不同的范围(分别位于派生类与基类) ...
- c/c++:重载 覆盖 隐藏 overload override overwrite
http://www.cnblogs.com/qlee/archive/2011/07/04/2097055.html 成员函数的重载.覆盖与隐藏成员函数的重载.覆盖(override)与隐藏很容易混 ...
- c++ 继承 虚函数与多态性 重载 覆盖 隐藏
http://blog.csdn.net/lushujun2011/article/details/6827555 2011.9.27 1) 定义一个对象时,就调用了构造函数.如果一个类中没有定义任何 ...
- 【C++】三大概念要分清--重载,隐藏(重定义,覆盖(重写)
{ c++三大概念要分清--重载,隐藏(重定义),覆盖(重写)} 重载 • 概念:在同一个作用域内:函数名相同,参数列表不同(参数个数不同,或者参数类型不同,或者参数个数和参数类型都不同),返回值类 ...
- Delphi中静态方法重载还是覆盖的讨论
Delphi中静态方法重载还是覆盖的讨论 新人学习Delphi的时候,容易搞不懂的一个问题,当子类方法和基类方法同名,并且参数也一样的时候,叫做什么呢?是覆盖,还是重载呢? 答案是隐藏父类方法. 一般 ...
- c++三大概念要分清--重载,隐藏(重定义),覆盖(重写)
重载,隐藏(重定义),覆盖(重写)—这几个名词看着好像很像,不过其实一样都不一样!! 综述: 说明:覆盖中的访问修饰符可以不同是指可以不用显示地用virtual:当访问修饰符改为const或者stat ...
- C++之重载覆盖和隐藏
继承体系下同名成员函数的三种关系 重载 在同一作用域内 函数名相同,参数列表不同(分三种情况:参数个数不同,参数类型不同,参数个数和类型都不同) 返回值类型可以相同也可以不同 重写(覆盖) 在不同作用 ...
随机推荐
- 你需要知道的九大排序算法【Python实现】之选择排序
一.选择排序 基本思想:选择排序的思想非常直接,不是要排序么?那好,我就从所有序列中先找到最小的,然后放到第一个位置.之后再看剩余元素中最小的,放到第二个位置--以此类推,就可以完成整个的排序工作了. ...
- android与javascript相互调用
下面这一节来介绍android和javascript是怎么相互调用的,这样我们的UI界面设计起来就简单多了,而且UI设计起来也可以跨平台.现在有好多web app前台框架了,比如sencha和jque ...
- jQuery插件开发 格式与解析3之$.extend()用途
前叙:$.extend()——用途:扩展和继承 1.Object extend() 用一个或多个对象扩展另一个对象,并返回已修改的原始对象.这对于简单继承是一个非常有用的实用工具. (1)扩展:(Do ...
- Android 之 资源文件的介绍及使用
Android 之 资源文件的介绍及使用 1.资源的简单介绍: 在res文件夹中定义:字符串.颜色.数组.菜单.图片.视频等:在应用程序中使用这些资源. 2.使用资源的长处:降低代码量,同一时候为 ...
- Linux(CentOS 5.5) Redis安装
一,什么是redis redis是一个key-value存储系统. 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset ...
- python字符串连接方式(转)
在python中有很多字符串连接方式,今天就在这里具体总结一下: ①.最原始的字符串连接方式:str1 + str2②.python 新字符串连接语法:str1, str2③.奇怪的字符串方式:str ...
- 找两个string[ ]里不同的元素
方法 1:string[] strListOne = new string[] {"Type", "Parent Id","Status"} ...
- Mysql的Error 1364
在安装mysql 5.5.8的最后一步,应用安全配置时, 弹出错误对话框, Error Nr.1364 authentication_string 解决办法: 1.暂时不要关闭该窗口,cmd命令,执行 ...
- VS2012 编写C++程序的时候DOS窗口一闪而过解决办法。
在我每次通过VS2012 运行C++程序的时候,DOS窗口在显示结果的时候都是一闪而过.这样让人没法观察输出的结果.经试验找到了一较好的解决办法: 首先包含头文件"stdlib.h" ...
- 对于js原型和原型链继承的简单理解(第二种,对象冒充)
关键代码 this.parent = Cat; this.parent.apply(this); function Cat(){ this.climb = function(){ aler ...