函数的重载,覆盖/重写,与隐藏

1.  函数重载(Overload):

普通的重载我们都知道是怎么回事。在面向对象的编程中,函数重载只能发生在同一个类当中

典型的重载重载就是类的构造函数,比如:无参构造函数,拷贝构造函数,赋值构造函数之间。

重载发生的条件是:仅仅函数的形参(数量或者类型)不同。

2. 函数覆盖/重写(Override):

函数覆盖(也就是重写)就是我们平时所说的类的多态性实现的时候发生的事情:

基类指针指向派生类,指针调用函数时派生类的函数就会覆盖基类函数。

覆盖发生的条件,就是多态性实现的条件

a.基类指针指向派生类;

b.基类的函数前有virtual声明为虚函数;

c.基类和派生类(函数名和参数等)完全相同!

3. 函数隐藏(Hide?):

其他类定义的函数,被类的同名函数屏蔽,好像被隐藏了。

(说成被覆盖了好像也解释得通,但是人家规定好“覆盖”和“隐藏”的意义了,就入乡随俗好了)

函数隐藏的条件:

a.首先要同名,不然就不是同一个函数了;

b.不同类的同名函数,假如满足函数覆盖,就会发生函数隐藏!

虽然b听起来很绝对,但是也很好记,关键是正确!

4. 举个栗子好了:

 1 class Base
 2 {
 3 public:
 4     virtual  void  f(float  x) { cout  <<  "Base::f(float)"  <<  endl; }
 5     void  g(float  x) { cout  <<  "Base::g(float)"  <<  endl; }
 6     void  h(float  x) { cout  <<  "Base::h(float)"  <<  endl; }            
 7 }
 8 
 9 class Derive
10 {
11 public:
12     virtual  void  f(float  x) { cout  <<  "Derive::f(float)"  <<  endl; }
13     void  g(int  x)     { cout  <<  "Derive::g(int)"  <<  endl; }
14     void  h(float  x)  { cout  <<  "Derive::h(float)"  <<  endl; }            
15 }

调用:
  Base *base = new Derive;
  base -> f(1.0);
  base -> g(2);
  base -> h(1.0);

会发生什么?根据上面的规则很好判断:

先看是否符合多态性的条件,只有Derive::f(float x)符合,所以会发生函数覆盖;

其他不符合的,就是发生函数隐藏,也就是由于指针指向派生类,说此时函数的调用只和派生类有关,和基类没有关系!

5. 覆盖和隐藏的选择

一间学校,基类是学生,派生类是:小学生,初中生,高中生;

函数有:吃饭,上课,考试;

吃饭是每个学生都要做的事情,而且做法一样,都是去食堂吃饭;

考试是部分学生(初高中生)需要做的事情,小学生减负不考试;

上课虽然是每类学生都要做的事情,但是每类学生的做法都不相同;

吃饭,考试,上课,对于每个派生类的共用性程度越来越低,这种情况下如何设定函数的模式呢?

首先,既然每个派生类都要实现相同的吃饭函数,就把吃饭放在基类中,作为基类的普通成员函数

派生类继承基类,自然就可以正常使用吃饭函数。

这叫做什么?就是普通的继承啊~

然后,上课是每个派生类都做但是做法都不相同的函数,很容易想到通过多态性实现。

具体来说就是在基类中声明上课是虚函数,然后在不同派生类中重写自己的上课函数,进行覆盖。

最好声明上课为纯虚函数,就不用在基类中实现上课函数了,因为基类的上课本来就没有特殊意义,只是一个接口。

这样基类就成了抽象类,不能实例化。

不过没关系,我们建议用指针实现类的实例化和函数调用。

最后,有大部分派生类可以使用考试函数,但是又不能让小学生考试,这种情况下怎么设定函数模式?

肯定不能是基类的普通成员函数,否则怎么实现?

第一种方法:

在基类中声明并实现考试函数为虚函数,在大部分派生类中不定义考试函数进行覆盖,

只在小学生类中重新定义一个空的考试函数,进行覆盖以实现多态性

第二种方法:

在基类中定义考试为普通成员函数,派生类通过继承使用她。

对于小学生来说,可以在类中重新定义一个空的考试函数,实现对基类考试函数的隐藏

从逻辑性来说,实现多态性会更容易理解一些。

猜你喜欢

转载自www.cnblogs.com/Younger-Zhang/p/10540430.html