C++学习笔记――多态性和虚函数

  多态性实现了接口和实现的分离。
  捆绑:将函数体和函数调用相联系成为捆绑。分为早捆绑和晚捆绑,早捆绑在程序运行之前完成,晚捆绑反之。
  C++中,虚函数实现晚捆绑。将基类的函数声明为virtual,对派生类的函数都将使用虚机制。实现运行时捆绑――晚捆绑。
  实现:VTABLE&Vptr:
  VTABLE:存放类中所有虚函数的地址
  Vptr:指向VTABLE的指针,使函数通过基类指针调用虚函数时能匹配正确。
如:
Class Base
{
      int param1;
  public:
      virtual void f(){ cout<<"base"<<endl;}
      virtual int g(){ return 0 ;}
};
Class Derived:public Base
{
     int param2;
  public:
      void f(){ cout << "deriverd"<< endl;}
      int  g(){ return 1; }
      virtual string F(){return "derived";}
};
上面两个类的VTABLE分别为:
          
 &Base::f
 &Base::g

 &Derived::f
 &Dervived::g
 &Derived::F
  每当创建一个含有虚函数的类时,编译器就为这个类创建一个VTABLE,,并且在这个类中放置指向VTABLE首地址的指针Vptr。一旦VPTR被初始化为指向相应的VTABLE,对象就知道自己的类型。当通过基类地址调用一个虚函数时,如
  Deriverd d;
  Base * bptr = & d;
  bptr-> g();
  此时,虽然进行了向上类型转换,程序运行仍然调用派生类对象d的g()函数,返回1。程序通过基类指针bptr指向对象d的的首地址,由于VPTR存于对象中的相同位置,编译器能够取出对象d的VPTR,通过指针偏移获得函数g()的地址,进行调用,完成了晚捆绑。晚捆绑访问VTABLE,所以调用虚函数时有额外的开销,对函数调用的效率有所影响。
纯虚函数:将上面代码修改,如下:
Class Base
{
   public:
      virtual void f()=0;
      virtual int g()=0;
};
  基类的虚函数声明为“=0”的形式即声明为纯虚函数。纯虚函数可以没有定义,并且含有纯虚函数的类变成抽象类,不准生抽象类的对象。
  派生类必须对基类所有的纯虚函数进行定义,否则仍然为抽象类,不能生成对象实例。
传值调用:对象切片问题
  设存在函数 void function(Base b);函数接受基类对象b,如果声明一个派生类对象
      Dervived d;
      function(d);此时会发生向上类型转换,将派生类对象转换为Base类型的,对于Base类型的对象只有一个数据成员,而派生类的对象有两个,发生向上类型转换时,发生对象切片,派生类的私有数据成员param2丢失。如下表所示,分别为切片以前和切片以后的对象部分:
                       
 Derived Vptr
 param1
 param2

 Derived Vptr
 param1

  虚机制不作用于构造函数和析构函数,在构造函数和析构函数中调用的虚函数都是函数的本地版本。对于构造函数,因为虚函数所属的子类对象可能还没有生成,析构函数反之,这时调用发生错误。
  可以有纯虚的析构函数,并且纯虚的析构函数必须有定义。虚析构函数的主要作用是防止实例化。

你可能感兴趣的:(职场,休闲)