1. 函数重载(Overload):编程
普通的重载咱们都知道是怎么回事。在面向对象的编程中,函数重载只能发生在同一个类当中!ide
典型的重载重载就是类的构造函数,好比:无参构造函数,拷贝构造函数,赋值构造函数之间。函数
重载发生的条件是:仅仅函数的形参(数量或者类型)不一样。spa
2. 函数覆盖/重写(Override):指针
函数覆盖(也就是重写)就是咱们平时所说的类的多态性实现的时候发生的事情:code
基类指针指向派生类,指针调用函数时派生类的函数就会覆盖基类函数。对象
覆盖发生的条件,就是多态性实现的条件:blog
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. 覆盖和隐藏的选择
一间学校,基类是学生,派生类是:小学生,初中生,高中生;
函数有:吃饭,上课,考试;
吃饭是每一个学生都要作的事情,并且作法同样,都是去食堂吃饭;
考试是部分学生(初高中生)须要作的事情,小学生减负不考试;
上课虽然是每类学生都要作的事情,可是每类学生的作法都不相同;
吃饭,考试,上课,对于每一个派生类的共用性程度愈来愈低,这种状况下如何设定函数的模式呢?
首先,既然每一个派生类都要实现相同的吃饭函数,就把吃饭放在基类中,做为基类的普通成员函数。
派生类继承基类,天然就能够正常使用吃饭函数。
这叫作什么?就是普通的继承啊~
而后,上课是每一个派生类都作可是作法都不相同的函数,很容易想到经过多态性实现。
具体来讲就是在基类中声明上课是虚函数,而后在不一样派生类中重写本身的上课函数,进行覆盖。
最好声明上课为纯虚函数,就不用在基类中实现上课函数了,由于基类的上课原本就没有特殊意义,只是一个接口。
这样基类就成了抽象类,不能实例化。
不过不要紧,咱们建议用指针实现类的实例化和函数调用。
最后,有大部分派生类可使用考试函数,可是又不能让小学生考试,这种状况下怎么设定函数模式?
确定不能是基类的普通成员函数,不然怎么实现?
第一种方法:
在基类中声明并实现考试函数为虚函数,在大部分派生类中不定义考试函数进行覆盖,
只在小学生类中从新定义一个空的考试函数,进行覆盖以实现多态性。
第二种方法:
在基类中定义考试为普通成员函数,派生类经过继承使用她。
对于小学生来讲,能够在类中从新定义一个空的考试函数,实现对基类考试函数的隐藏。
从逻辑性来讲,实现多态性会更容易理解一些。