虚函数和重载之间的关系思考(未编写完)

先说重载

我们说重载是C++中允许同名函数存在的方法

int add(int i,int j);
float add(float i,float);

而在c中,函数名是唯一的,所以为了区分int和float版本的add,你需要给它们起不同的名字,比如将int的命名为add_int,将float的命名为add_float,这样做的坏处就是程序员要记住很多的函数名,虽然这些函数的功能是一样的,而且也不直观。

函数重载可以根据参数的类型,自动调用合适的重载函数。程序不用返回值辨别是因为有的函数是没有返回值的void类型

函数重载的要求我们知道是

函数要么参数类型不同,要么参数的个数不同,或者两者兼有。重载可以是全局函数也可以是局部函数

重载的时候我们有个问题就是涉及到派生继承时,名字的遮蔽问题

当派生类和基类中有同名函数时,甚至各有重载时,基类中的重载函数都被忽略

意思说派生类遮蔽了基类同名函数,导致调用使用重载时即使派生类没有对应的重载函数也不会调用基类的重载函数,导致没有重载函数匹配调用而调用失败
 如果说有重载关系,那么也是基类类的两个 func 构成重载,而派生类的两个 func 构成另外的重载。 而不会基类和派生类构成四个重载

子类中的同名函数将父类中的同名函数给隐藏了,只要子类中的函数是可见的,通过子类的对象调用父类的同名函数是不合法的,只能调用子类自身的同名函数。这就是所谓的名字隐藏。

再说虚函数

 

我们来研究两者的情况

来看一个例子

class base{

public:

  virtual int fcn();

};

class d1:public base{

public:

  int fcn(int);

}

我们知道针对虚函数的可以叫覆盖,而重载那边叫屏蔽(隐藏)

成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。

覆盖是针对虚函数来说的。就是说派生类给出了自己的实现(参数个数和类型必须相同)
屏蔽只是说内层定义域定义了一个和外层定义域相同的函数名。(参数个数和类型没要求一致)

重载时名字屏蔽,基类的对象可以调用基类的重载吗?

我们来看一段编译实验

可以看出基类的对象确实调用了基类的重载函数,可能你会说:那你这是因为是基类的对象才会调用基类重载函数吧,如果是派生类呢?

我们再来看一段实验

 

然后看一下错误信息

 

 

 错误信息中表明确实就是屏蔽了基类的重载,且在派生类的重载中找不到所需的字符串型重载函数,发生错误

 

 

 

遮掩(屏蔽)只发生在使用派生类的对象来调用成员函数的情况下,而不适合于用基类指针或引用(虽然指向派生类的对象)来调用成员函数的情况

因为基类指针和引用调用时作用域还是在基类,而不是派生类,所以不发生屏蔽现象

如何破除这种屏蔽呢?我们可以看一篇文章:https://blog.csdn.net/iicy266/article/details/11906697

里面讲到,如果在调用派生类中的重载时还是想用基类重载,必须在对应派生类里加上对基类重载的声明,即在派生类中加入

using 基类名::重载函数名;

一个using声明只能指定一个名字,不能指定形参表,using将所有基类中的重载实例加载到该派生类的作用域中,即在同一作用域内,可以实现重载。

这是与编译器查找顺序有关的。

 

如果说虚函数在派生类中重写时变动了其形参列表会怎样呢?

虚函数重载时,改变函数返回类型,其余相同,则程序报错

若仅满足函数名相同,其余的参数个数类型顺序不同,则会作为普通的成员函数重载,则此时会触发名字遮蔽问题

可以看这篇文章的讨论https://bbs.csdn.net/topics/360095263?list=14151412

里面提到的

 

 可以看到,里面在虚函数的重载,或者我们叫重写时,改变了参数列表,则fcn函数作为普通成员函数重载,发生名字遮蔽

(待补充……)

 

关于指向派生类对象的基类指针调用虚函数的情况

我们可以来看一个有意思的讨论:

https://bbs.csdn.net/topics/390828461?spm=1035.2023.3001.6557&utm_medium=distribute.pc_relevant_bbs_down_v2.none-task-bbs-2~default~ESMLT~Rate-3-390828461-bbs-360095263.pc_relevant_bbs_down_v2_mltv1&depth_1-utm_source=distribute.pc_relevant_bbs_down_v2.none-task-bbs-2~default~ESMLT~Rate-3-390828461-bbs-360095263.pc_relevant_bbs_down_v2_mltv1

 

虚基类

复杂的继承中,先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用本派生类的构造函数

即class A:public B,virtual C时,调用顺序为C、B、A

运用虚继承解决派生继承中出现的二义性问题

我们在常见的菱形继承中,由于不同路线上产生了多个同名的基类成员复制,在调用该成员时必须加上作用域符::来指明是哪个派生类中的复制

这就要用到虚继承来简化调用时的这种::的复杂声明

虚继承(虚基类)相当于所有声明为虚基类的派生类中继承的基类成员都将被忽略,只保留公共的基类的一份复制

如果基类(有派生类声明它为虚基类)中定义了带形参的构造函数,但没有定义默认形式的构造函数,则在整个继承结构中,直接和间接继承该类的子类都要在类名后缀上该类的调用即

:函数名(形参名)

来初始化这个虚基类中的数据成员

 

posted @ 2022-07-04 00:30  Dantezhenniubi  阅读(383)  评论(0)    收藏  举报
/*鼠标戏龙*/ div#top_nav { display:none } div#bannerbar {display: none;}