简述虚函数表

前段时间我在博客中简单地说了下C++的虚函数,所谓虚函数,就是C++实现多态性的方法。那么编译器是如何识别虚函数的呢?据百度百科描述,C++并未规定用何种方法实现虚函数,但是大部分编译器厂商都选择使用虚函数表这种方法,那到底什么是虚函数表???

 

虚函数表,称为V-Table。虚函数表是一片连续的内存区域,每个内存单元存放着JMP指令地址。

看到这里,可能会比较懵逼,啥是内存单元,啥是JMP指令?我们先插一段汇编语言的内容,帮助更好的理解虚函数表。


备用知识:

  • 每个内存单元都有自己的内存地址,内存单元存放数据。
  • 每个内存单元存放一个字节的数据,为8位。对于不同的机器,一个字为不同的长度,但都是字节的整数倍。如8086的机器为16位,其字长为2字节。一个字长为计算机的一个处理单元。
  • JMP指令:无条件跳转。类似于高级语言中的goto语句。

虚函数工作原理:

C++中规定了虚函数的行为,即虚函数是干什么的,但是并未规定虚函数应该怎么实现。因此这是编译器需要解决的问题。通常来说,编译器会利用虚函数表(V-Table)解决虚函数的问题。

虚函数表实际上是一个数组,其中存储了为类对象进行声明的虚函数的地址。

懵逼。。这里有许多问题需要解决:

  1. 既然虚函数的地址存放在V-Table中,那么V-Table的地址从哪找?
  2. V-Table有多少?是一个V-Table存放着所有的虚函数地址,还是一个V-Table存放一定数量的地址?
  3. 具体的过程是如何的?

我们一个一个解答:

  1. 我们在声明了一个虚函数类的对象的同时,这个对象被添加了一个隐式成员。该成员保存了指向虚函数地址数组的指针。

       函数地址数组:函数是有地址的,将函数的地址存放在一个数组中,就是函数地址数组或函数指针数组。

       这个成员对象保存的就是这个数组的指针,而该数组就是虚函数表(V-Table)。(不知道这样说清不清楚。)

    2.  只要包含虚函数的类就会有一个虚函数表,当这个类是基类时,它的派生类也会有相应的虚函数表。当一个类有多个对象的时候,这些对象共享一个虚函数表。

        例如:基类对象包含一个指针,该指针指向基类中所有虚函数的地址表,派生类将包含一个指向独立地址表的指针。两个表是相互独立的!当派生类重新实现了基类中的虚函数,那么派生类的虚函数表将保存新的函数地址。如果派生类并未对虚函数做改动,那么虚函数表将保存原始函数地址。也就是说,派生类的虚函数表进行改动并不会对基类的虚函数表有影响。

    3. 具体过程:先看一段伪代码

class Pets{
private
    String type;
    String name;
public:
    virtual void show_name(); 
    virtual void show_type();
};

class Dogs: public Pets{
private:
    int age;
    String ownerName;
public:
    void show_name(){}
    virtual void show_age();
};

这段代码描述宠物基类和继承宠物基类的狗类。

int main(){
    Dogs dog("mammal","Bob",2,"Peter");
    Pets *pets = &dog;
    pets->show_name();
    return 0;
}

当执行pets->show_name()时,会经历以下过程:

  1. 通过pets找到隐藏成员的地址,并通过地址的值找到改数据表示的虚函数表;
  2. 获取表中内容为地址7800的地址(就是找到调用的函数)
  3. 前往地址7800,并执行函数。

 


总结:

虚函数的一种使用是通过虚函数表实现的,所以不可避免的在内存与速度方面都会有影响:

  1. 每个对象的大小都会增大一个存储地址的空间,用来存放隐藏成员代表指向的地址。
  2. 对于每个含有虚函数的类,编译器都会创建一个虚函数表;
  3. 每次调用虚函数,都需要经历一次寻址过程,到虚函数表中寻找虚函数地址,耗费了时间。

关于虚函数使用总结:

  1. 构造函数不能是虚函数。当初始化派生类对象的时候,将调用派生类的构造函数,之后派生类的构造函数又会调用基类中的构造函数,这种顺序不同于继承机制,所以派生类不能继承基类的构造函数,因此将构造函数声明称虚函数没有用。
  2. 析构函数应该声明为虚函数。前文讲过,不再赘述。
  3. 友元不能是虚函数,因为虚函数必须是成员函数,而友元不是成员类。但是友元函数可以使用虚函数。

虚函数概念及使用

C++纯虚函数

虚析构函数与纯虚析构函数

 

参考文献:

《C++ Primer Plus》

  • 12
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值