OOP12

OOP12 虚机制与多态

静态编联与动态编联

  • 编联是指计算机程序自身彼此关联的过程,也就是把一个标识符名和一个存储地址联系在一起的过程
  • 静态编联(早绑定,静态绑定)是指在编译阶段完成的编联。支持编译时多态,也称静态多态,即在编译阶段由编译系统根据操作的对象或对象类型确定调用哪个同名函数。函数重载和运算符重载都是静态编联即编译时多态
  • 动态编联(晚绑定,动态绑定)是指在运行阶段完成的编联。支持运行时多态,也称动态多态,在运行阶段临时确定具体调用哪个同名函数。C++通过继承和虚函数实现动态多态

虚函数

  • 虚函数是指类中用关键字virtual声明的成员函数
  • 虚函数的声明格式
    virtual <返回类型> <成员函数名>(<形参表>)[const];
  • 虚函数具有与普通成员函数相同的定义格式,不要加virtual
  • 派生类中的虚函数:
    ① 继承自基类的虚函数
    ② 新定义的虚函数(函数名不同于基类中的虚函数)
    ③ 覆盖(override),函数名、形参表与基类虚函数相同,返回类型与基类虚函数返回类型相容,virtual关键字可省略
class Shape{
public:  virtual void Show( ) { cout<Area( )<

虚拟表实现

  • 虚拟表(虚函数表,虚表,VTable)是C++编译器为了达到动态绑定的目的,为每一个含有虚函数的类都生成的一个表
  • 生成虚拟表的条件是类中至少有一个虚函数;时机是当首次创建该类实例对象时,在内存中同时创建该类的虚拟表;个数是一个类只有一个,且同一个类的不同对象共享该虚拟表
  • 实现上虚拟表就是一个函数指针数组,表中的每一项都指向一个虚函数实现在内存中的存储地址
  • 编译器为虚拟表所属类增加一个指针型数据成员vptr,当创建类对象时,其被初始化为该虚拟表在内存中的存储地址

虚析构函数

  • 析构函数常声明为虚函数
  • 虚析构函数的声明格式
    virtual ~<类名>( );
  • 如果一个类的析构函数是虚函数,那么由它派生的所有子类的析构函数也是虚函数
  • 析构函数被声明为虚函数后,就能保证通过基类对象引用或对象指针调用它所关联的派生类对象的析构函数,从而进行不同派生类对象的清理工作

关于虚函数的注意

  • 构造函数不能声明为虚函数。构造函数是在创建对象时被调用,完成对象的初始化,此时对象还没有完全建立。虚函数作为运行时多态性的基础,主要是针对对象的,而构造函数是在对象产生之前运行的。所以将构造函数声明为虚函数是没有意义的
  • 静态成员函数不能声明为虚函数。因为静态成员函数不属于某一个对象,没有多态性的特征
  • 内联成员函数不能声明为虚函数。因为内联函数的执行代码是明确的,在编译时已被替换,没有多态性的特征。如果将那些在类体内定义的成员函数声明为虚函数,此时函数不是内联函数,而以多态性出现
  • 析构函数可以声明虚函数,且往往被声明为虚函数。一般来说,若某类中有虚函数,则其析构函数也应当声明为虚函数

虚函数的访问

  • 虚函数中调用的非虚函数,采用静态编联,使用本地版本
  • 虚函数中调用的虚函数,采用动态编联
  • 非虚函数中调用的虚函数,采用动态编联
  • 构造函数中调用的虚函数,采用静态编联,使用本地版本
  • 析构函数中调用的虚函数,采用静态编联,使用本地版本

纯虚函数与纯虚定义

  • 纯虚函数是指那些在基类中无法实现或不需要实现,而在派生类中再给出具体实现的虚函数
  • 纯虚函数的声明格式
    virtual <返回类型> <函数名>(<参数表>) [const]=0;
  • 纯虚定义是指对纯虚函数给出缺省实现(定义)
    virtual <返回类型> <函数名>(<参数表>) [const]=0
    { /* 略 */ }

抽象类和具体类

  • 含有一个或多个纯虚函数的类称为抽象类
  • 全部非静态成员函数均为纯虚函数的类称为纯抽象类
  • 抽象类自身不能被实例化,只能通过派生类实例化
  • 可以实例化的类称为具体类
  • 可以声明抽象类的对象引用或指针,并指向派生类对象,进而访问派生类的成员,实现多态
  • 抽象类派生出新类后,如果派生类给出所有纯虚函数的实现,则该派生类就不再是抽象类,可以实例化,如果没有给出全部纯虚函数的实现,只实现了部分,它仍然是抽象类

函数重载,覆盖,隐藏

函数重载(overload)的特征
-相同的范围,如在同一个类中
函数名相同
函数形参表不同
virtual关键字可有可无

函数覆盖的特征

  • 不同的范围,分别位于派生类与基类
  • 函数名相同
  • 函数形参表相同
  • 函数返回类型相容
  • 基类函数必须有virtual关键字

函数隐藏的特征

  • 不同的范围,分别位于派生类与基类
  • 函数名相同
  • 函数形参表不同,此时,不论有无virtual关键字,基类的函数将被隐藏
  • 函数形参表相同,但是基类函数没有virtual关键字,此时,基类的函数被隐藏

你可能感兴趣的:(OOP笔记)