参考:
C++中的继承
多继承下不同基类之同名函数的使用

一、重载、覆盖(重写)
a. 成员函数被重载的特征:
(1). 相同的范围(在同一个类中);
(2). 函数名字相同;
(3). 参数不同;
(4). virtual关键字可有可无。
b. 覆盖是指派生类函数覆盖基类函数。
(1). 不同的范围(分别位于基类和派生类);
(2). 函数名字相同;
(3). 参数相同;
(4). 基类函数必须有virtual关键字。
c. “隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1). 如果派生类的函数与基类函数同名,但是参数不同。此时,不论有无virtual, 基类的函数将被隐藏;
(2). 如果派生类的函数与基类的函数同名,并且形参也相同,但是基类函数没有virtual,此时,基类的函数被隐藏。

二、隐藏和覆盖
在C++的继承中我们知道派生类可以继承基类的成员变量和成员函数,那么当派生类继承基类的成员变量和成员函数时自己也有同名的成员变量和同名且同参数列表的成员函数时是如何处理的呢?
遇到这类情况C++的处理方式为隐藏和覆盖

1、隐藏

  • 派生类将继承的基类的同名的成员变量和成员方法隐藏起来,通过派生类只能访问到自己的成员变量和成员方法。若想要访问基类的成员变量和成员方法需加上基类的作用域。隐藏以后的直接效果就是:无论在派生类的内部或者外部(通过派生类成员)访问该成员;全都是访问派生类的同名成员; 如果在派生类内部或者外部(通过派生类成员)访问同名的成员函数,则需要根据函数调用的规则来调用派生类的同名成员函数;

2、覆盖(重写)

  • 覆盖往往与继承的类中有virtual修饰的函数有关。virtual修饰的函数为虚函数。而要构成覆盖就得满足基类中有virtual修饰的函数,而在派生类中有与基类中的虚函数同名且同参数列表的函数,那么派生类中的的该函数就会将基类中的函数覆盖,调用时无法调用基类中的函数。在子类中定义了一个与父类虚函数完全相同的函数,那么这个子类的函数就是重写了父类的虚函数,此时这个子类的函数就是虚函数,如果不显示的加上virtual修饰,编译器也会默认为虚函数。

  • 覆盖(重写)达到的效果:

    • 在子类中重写了父类的虚函数,那么子类对象调用该重写函数,调用到的是子类内部重写的虚函数,而并不是从父类继承下来的虚函数;(这其实就是动态多态的实现);
    • 在子类中重写了父类的虚函数,如果用一个父类的指针(或引用)指向(或引用)子类对象,那么这个父类的指针或用引用调用该重写的虚函数,调用的是子类的虚函数;相反,如果用一个父类的指针(或引用)指向(或引用)父类的对象,那么这个父类的指针或用引用调用该重写的虚函数,调用的是父类的虚函数。

3、总结

  • 隐藏和覆写的主要区别就在于被继承的基类中函数有无virtual(是不是虚函数)。为了通过父类指针指向继承的不同的子类对象来体现多态,指向子类对象的父类指针调用父子类同名,同参,同返回类型的函数,基于隐藏和覆写的区别,会分别调用到父类和子类的函数,这也是二者主要需要区分和应用的地方

三、多态
C++多态包括编译时多态和运行时多态,

  • 编译时多态体现在函数重载和模板上,
  • 运行时多态体现在虚函数上。虚函数:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。

四、多继承下不同基类之同名函数的使用
多继承下两个以上基类有相同名称的成员函数时,派生类对象引用该名称函数时,若不做任何处理,将不能正常工作。其原因在于,重载规则不适用于跨越多个类的情况。有两种基本的方法:一是使用时明确指出用到哪个基类的同名函数;

class A {
public:
       int func ( int );
       void func ( char );
       // ...
};

class B {
public:
       double func ( double );
       // ...
};

class AB : public A, public B {
public:
       // ...
};

void f1 ( AB* ab )
{
       ab->func ( 1 ); // 出现歧义
       ab->A::func ( 1 ); // 明确地指出是用哪个基类的同名函数
       ab->B::func ( 1 );
}