虚成员函数的实现(多态)

虚成员函数是动态确定的(在运行时)。也就是说,成员函数(在运行时)被动态地选择,该选择基于对象的类型,而不是指向该对象的指针/引用的类型。这被称作“动态绑定”。大多数的编译器使用以下的一些的技术:如果对象有一个或多个虚函数,编译器将一个
隐藏的指针放入对象,该指针称为“virtual-pointor”或“v-pointer”。这个v-pointer指向一个全局表,该表称为“虚函数表(virtural-table)”或“v-table”。

编译器为每个含有至少一个虚函数的类创建一个v-table。例如,如果Cirle类有虚函数ddraw()move() 和 resize(),那么将有且只有一个和Cricle类相关的v-table,即使有一大堆Circle对象。并且每个 Circle对象的 v-poiner将指向 Circle的这个 v-table。该 v-table自己有指向类的各个虚函数的指针。例如,Circle 的v-table 会有三个指针:一个指向Circle::draw(),一个指向 Circle::move(),还有一个指向Circle::resize()

在分发一个虚函数时,运行时系统跟随对象的 v-pointer找到类的 v-table,然后跟随v-table中适当的项找到方法的代码。

以上技术的空间开销是存在的:每个对象一个额外的指针(仅仅对于需要动态绑定的对象),加上每个方法一个额外的指针(仅仅对于虚方法)。时间开销也是有的:和普通函数调用比较,虚函数调用需要两个额外的步骤(得到v-pointer的值,得到方法的地址)。由于编译器在编译时就通过指针类型解决了非虚函数的调用,所以这些开销不会发生在非虚函数上。
举个例子:

class Class1   {
   public :
      data1;
      data2;
      memfunc();
      virtual vfunc1();
      virtual vfunc2();
      virtual vfunc3();
};
Class1 物件實體在記憶體中佔據這樣的空間:

每一個由此類別衍生出來的物件,都有這麼一個 vptr。當我們透過這個物件呼叫虛擬函
式,事實上是透過 vptr   找到虛擬函式表,再找出虛擬函式的真正位址。
奧妙在於這個虛擬函式表以及這種間接呼叫方式。虛擬函式表的內容是依據類別中的虛
擬函式宣告次序,一一填入函式指標。衍生類別會繼承基礎類別的虛擬函式表(以及所
有其他可以繼承的成員),當我們在衍生類別中改寫虛擬函式時,虛擬函式表就受了影
響:表中元素所指的函式位址將不再是基礎類別的函式位址,而是衍生類別的函式位址。
看看這個例子:
class Class2 : public Class1 {
   public :
     data3;
     memfunc();
     virtual vfunc2();
};

於是,一個「指向   Class1   所生物件」的指標,所呼叫的   vfunc2   就是 Class1::vfunc2,而
一個「指向   Class2   所生物件」的指標,所呼叫的 vfunc2   就是   Class2::vfunc2。
動態繫結機制,在執行時期,根據虛擬函式表,做出了正確的選擇。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值