- 每个类定义自己的作用域,在这个作用域内定义类的成员。当存在继承关系时,派生类的作用域嵌套在其基类的作用域内。因为有了嵌套作用域,派生类才能像使用自己的成员一样使用基类成员。
- 一个对象、引用或指针的静态类型决定了该对象的哪些成员是可见的。即使动态类型与静态类型不一致(比如基类指针或引用指向派生类)。
名字冲突与继承
- 和其他作用域一样,派生类也能重新定义在其直接基类或间接基类中的名字,此时定义在内层作用域的名字将隐藏定义在外层作用域的名字。
- 可以通过作用域运算符来使用被隐藏的基类成员。如
Base::mem;
(作用域运算符将覆盖掉原有的查找规则,指示编译器从Base类的作用域开始查找mem)。 - 除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字。
函数调用的解析过程
假定调用p->men(),则依次执行以下4步:
- 首先确定p的静态类型。
- 在p的静态类型对应的类中查找mem。如果找不到,则依次在直接基类中查找直至到达继承链的顶端。如果还是找不到,则编译器报错。
- 一旦找到mem,就进行常规类型检查以确定对于当前找到的mem,本次调用是否合法。
- 假设合法,则编译器将根据mem是否是虚函数而产生不同的代码:
- 如果mem是虚函数且我们通过引用或指针进行的调用,则编译器产生的代码将在运行时确定到底运行虚函数的哪个版本,依据是对象的动态类型。
- 如果mem不是虚函数或是通过对象(而非引用或指针)进行的调用,则编译器将产生一个常规函数调用。
基类与派生类中的虚函数必须有相同的形参列表。
如果两者的虚函数接受的实参不同,则无法通过基类的引用或指针调用派生类的虚函数。
因为如果两者的虚函数形参列表不同,则派生类的虚函数就无法覆盖基类的虚函数。