虚函数实现

转载 2015年11月20日 10:49:15
1、c++实现多态的方法

其实很多人都知道,虚函数在c++中的实现机制就是用虚表和虚指针,但是具体是怎样的呢?从more effecive c++其中一篇文章里面可以知道:是每个类用了一个虚表,每个类的对象用了一个虚指针。具体的用法如下:

class A
{
public:
    virtual void f();
    virtual void g();
private:
    int a
};

class B : public A
{
public:
    void g();
private:
    int b;
};

//A,B的实现省略

因为A有virtual void f(),和g(),所以编译器为A类准备了一个虚表vtableA,内容如下:

A::f 的地址
A::g 的地址

B因为继承了A,所以编译器也为B准备了一个虚表vtableB,内容如下:

A::f 的地址
B::g 的地址

注意:因为B::g是重写了的,所以B的虚表的g放的是B::g的入口地址,但是f是从上面的A继承下来的,所以f的地址是A::f的入口地址。

然后某处有语句 B bB;的时候,编译器分配空间时,除了A的int a,B的成员int b;以外,还分配了一个虚指针vptr,指向B的虚表vtableB,bB的布局如下:

vptr : 指向B的虚表vtableB
int a: 继承A的成员
int b: B成员

当如下语句的时候:
A *pa = &bB;

pa的结构就是A的布局(就是说用pa只能访问的到bB对象的前两项,访问不到第三项int b)

那么pa->g()中,编译器知道的是,g是一个声明为virtual的成员函数,而且其入口地址放在表格(无论是vtalbeA表还是vtalbeB表)的第2项,那么编译器编译这条语句的时候就如是转换:call *(pa->vptr)[1](C语言的数组索引从0开始哈~)。

这一项放的是B::g()的入口地址,则就实现了多态。(注意bB的vptr指向的是B的虚表vtableB)

另外要注意的是,如上的实现并不是唯一的,C++标准只要求用这种机制实现多态,至于虚指针vptr到底放在一个对象布局的哪里,标准没有要求,每个编译器自己决定。我以上的结果是根据g++ 4.3.4经过反汇编分析出来的。

2、两种多态实现机制及其优缺点

除了c++的这种多态的实现机制之外,还有另外一种实现机制,也是查表,不过是按名称查表,是smalltalk等语言的实现机制。这两种方法的优缺点如下:

(1)、按照绝对位置查表,这种方法由于编译阶段已经做好了索引和表项(如上面的call *(pa->vptr[1]) ),所以运行速度比较快;缺点是:当A的virtual成员比较多(比如1000个),而B重写的成员比较少(比如2个),这种时候,B的vtableB的剩下的998个表项都是放A中的virtual成员函数的指针,如果这个派生体系比较大的时候,就浪费了很多的空间。

比如:GUI库,以MFC库为例,MFC有很多类,都是一个继承体系;而且很多时候每个类只是1,2个成员函数需要在派生类重写,如果用C++的虚函数机制,每个类有一个虚表,每个表里面有大量的重复,就会造成空间利用率不高。于是MFC的消息映射机制不用虚函数,而用第二种方法来实现多态,那就是:

(2)、按照函数名称查表,这种方案可以避免如上的问题;但是由于要比较名称,有时候要遍历所有的继承结构,时间效率性能不是很高。(关于MFC的消息映射的实现,看下一篇文章)

3、总结:

如果继承体系的基类的virtual成员不多,而且在派生类要重写的部分占了其中的大多数时候,用C++的虚函数机制是比较好的;

但是如果继承体系的基类的virtual成员很多,或者是继承体系比较庞大的时候,而且派生类中需要重写的部分比较少,那就用名称查找表,这样效率会高一些,很多的GUI库都是这样的,比如MFC,QT

C++中虚函数是怎样实现的

C++中虚函数是怎样实现的
  • A_LMY
  • A_LMY
  • 2016年03月04日 16:21
  • 709

c++虚函数实现机制及内存模型

前言 大家都应该知道C++的精髓是虚函数吧? 虚函数带来的好处就是: 可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时决定该调用基类的函数还是继承类的函...
  • mightySheldor
  • mightySheldor
  • 2015年11月19日 15:35
  • 1920

【C++拾遗】 C++虚函数实现原理

原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/50454819我们知道,与C语言相比,C++在布局和存取时间上的额外开销主要是由虚...
  • Xiejingfa
  • Xiejingfa
  • 2016年01月04日 15:47
  • 1429

虚函数的作用及其底层实现机制

1. C++中虚函数的作用和多态虚函数: 实现类的多态性关键字:虚函数;虚函数的作用;多态性;多态公有继承;动态联编C++中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在...
  • iFuMI
  • iFuMI
  • 2016年04月07日 18:10
  • 1726

C++虚函数在基类中不实现导致的报错

今天遇到了一个BUG,出错如下图1所示,是什么matrix()函数未定义,引用自某类A(图1中PinholeCamera类)所在文件中的vtable。 我搜了一下整个A所在的文件也没有找到vtabl...
  • IceTeaSet
  • IceTeaSet
  • 2017年01月17日 16:16
  • 910

虚函数实现原理

虚函数是很多编程语言中一个特性,比如c#,java,当然在c++语言中也有。这三种语言都是面向对象的语言。我们都知道面向对象语言有三个最基本的特征就是:继承,多态,封装。在c++语言中,这种多态的特征...
  • smilesundream
  • smilesundream
  • 2017年04月27日 17:05
  • 431

C++虚函数详解&实现机制&多态性

转载:http://blog.chinaunix.net/uid-24178783-id-370328.html
  • tcherry
  • tcherry
  • 2014年10月07日 15:03
  • 1026

Java语言的虚函数是怎么样的?

起因:刷题是遇到一个基础题,题如下: 以下关于面向对象的描述错误的是: 面向对象的基本特性是封装,继承和多态 构造函数不可以是虚函数,析构函数可以是虚函数 子类重新定义父类虚函数的方法叫做重载...
  • wj01111
  • wj01111
  • 2017年01月20日 17:11
  • 694

C++虚函数绑定的编译器实现

编译器为每个包含了虚函数的类创建一个表(vtable),在表中编译器放置特定类的虚函数地址,在每个带有虚函数的类中,编译器为每个类对象秘密的放置一个vpionter指针 ,指针指向vtalbe。通过基...
  • u012884354
  • u012884354
  • 2015年06月30日 10:08
  • 731

纯C语言简单模拟C++的虚函数表

多态,面向接口编程等设计方法并没有绑定到任何特定的语言上,使用纯C也可以实现简单的多态概念。下面给出一个非常简单粗糙的例子,只为说明概念。 父类Animal定义 文件:animal.h#ifndef...
  • smstong
  • smstong
  • 2016年02月15日 18:14
  • 2453
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:虚函数实现
举报原因:
原因补充:

(最多只允许输入30个字)