第01讲 多态性和虚函数  

8.1 多态性

8.1.1静态联编中的赋值兼容性和名字支配规律类的对象和调用的函数一一对应,程序编译时即可确定对象调用哪一个函数,称为静态联编。

  通过指针调用成员函数时:
  所调用成员函数为指针所属类的成员函数
  即由赋值兼容规则决定指针调用的成员函数
  第八章 多态性和虚函数 - 图1
  第八章 多态性和虚函数 - 图2
  第八章 多态性和虚函数 - 图3
  8.1.2动态联编的多态性
  要实现程序运行时决定指针所调用的函数是基类的还是派生类的,即:动态联编。
  可利用虚函数实现动态联编
  第八章 多态性和虚函数 - 图4
  第八章 多态性和虚函数 - 图5
  

8.2 虚函数

8.2.1虚函数的定义

  虚函数的格式:
  virtual double area(){return 0;}
  虚函数的调用规则:
  根据当前对象,优先调用对象本省的虚成员函数。
  虚函数不能是静态成员。
  8.2.2 虚函数实现多态性的条件
  使用虚函数产生多态的3个前提:
  1.类之间的继承关系满足赋值兼容性规则;
  2.改写了同名虚函数;
  3.根据赋值兼容性规则使用指针(或引用)。
  其中前提3分为两种情况:
  1.按赋值兼容性规则使用基类指针(或引用)访问虚函数;
  2.把指针(或引用)作为函数参数,即这个函数不一定是类的成员函数,可以是普通函数,而且可以重载。【P171中的display函数】

8.2.3构造函数和析构函数调用虚函数

  重要规则:采用静态联编,即只调用自己的类或基类中定义的函数,但不是任何在派生类中重定义的虚函数。
  P83
  new和构造函数
  delete和析构函数
  标准c++不支持虚构造函数
  支持虚析构函数,如果基类的虚析构函数,则派生类的析构函数是否用virtual说明,均为虚析构函数;如派生类未定义析构函数,则编译器生成的也是虚析构函数。

8.2.4 纯虚函数与抽象类

  1.纯虚函数的格式
  class 类名
  {
  virtual 函数类型 函数名(参数列表)=0;
  };
  2.抽象类
  包含纯虚数的类称为抽象类。
  抽象类的派生类如果没有实现抽象类中的全部纯虚函数,这个派生类依旧是抽象类。
  纯虚函数与空的虚函数是不同的:
  1.virtual void area()=0;
  2.virtual void area(){}

8.3 多重继承与虚函数

  多重继承可以被视为多个单一继承的组合,因此,分析多重继承情况下的虚函数调用与分析单一继承有相似之处。例如设计下面的类:
  【例8.5】多重继承使用虚函数。
  #include
  using namespace std;
  class A {
  public:
  virtual void f( ){cout<<"Call A"<  };
  class B {
  public:
  void f( ) {cout<<"Call B"<  };
  class C : public A, public B {
  public:
  void f( ) {cout<<"Call C"<  };
  void main( ){
  A pa;
  B
pb;
  C *pc, c;
  pa = &c;
  pb = &c;
  pc = &c;
  pa -> f( ); //输出Call C
  pb -> f( ); //输出Call B
  pc -> f( ); //输出Call C
  }
  程序运行结果如下:
  Call C
  Call B
  Call C
  上面的所有调用将实际调用C中的虚函数f,
  即输出“Call C”。

8.4 类成员函数的指针与多态性

  在派生类中,当一个指向基类成员函数的指针指向一个虚函数,并且通过指向对象的基类指针(或引用)访问这个虚函数时,仍发生多态性。
  【例8.6】使用基类成员函数的指针产生多态型。
  #include
  using namespace std;
  class base {
  public:
  virtual void print( )
  { cout << “In Base” << endl; } //虚函数
  };
  class derived : public base {
  public:
  void print( )
  { cout << “In Derived” << endl; } //虚函数
  };
  void display( base pb, void( base ::pf )( ) )
  { ( pb->*pf)( );}
  
  void main( )
  {
  base b;
  derived d;
  display( &b, base :: print ); //输出In Base
  display( &d, base :: print ); //输出In Derived
  }