Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7278554
  • 博文数量: 512
  • 博客积分: 12019
  • 博客等级: 上将
  • 技术积分: 6857
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-01 16:46
文章分类

全部博文(512)

文章存档

2024年(2)

2022年(2)

2021年(6)

2020年(59)

2019年(4)

2018年(10)

2017年(5)

2016年(2)

2015年(4)

2014年(4)

2013年(16)

2012年(47)

2011年(65)

2010年(46)

2009年(34)

2008年(52)

2007年(52)

2006年(80)

2005年(22)

分类: C/C++

2012-08-21 11:49:37

C++中的虚函数的实现一般是通过虚函数表(C++规范并没有规定具体用哪种方法,但大部分的厂商都选择此方法)。  类的虚函数表是一块连续的内存,每个中记录一个JMP指令的地址。
  
编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一行。如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。   

虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。这 样,在有虚函数的类的实例中分配了指向这个表的指针的内存,所以,当用父类的指针来操作一个子类的时候,这张虚函数表就显得尤为重要了,它就像一个地图一 样,指明了实际所应该调用的函数。   编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着可以通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。


以上是对虚函数表的描述。要注意编译器是为每个有虚函数的类生成一个虚函数表,当创建对象时候,便在对象内存开始处插入了对应的类的虚函数表地址(可参考汇编来看看)。
无论该虚函数是public、private、还是protected(我们一般习惯于用public,但private和protected也会视范围而用)。在此重点要理解编译器这种产生虚函数表的方式。另外理解这个还要从对象内存地址、函数地址的实际值来思考。

看下面的测试

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. class A
  4. {
  5.   //private:a
  6. protected:
  7.    virtual void f() {printf("base class ");}
  8. public:
  9.     //virtual void f() {printf("base class");}
  10.     void test(){f();}
  11. };


  12. //class B : private A
  13. class B : public A
  14. {
  15. //public:
  16. //private:
  17. protected:
  18.   virtual  void f() { printf("sub class\n");}
  19. };



  20. int main(int argc, char *argv[], char *env[])
  21. {
  22.         A* p = new B();
  23. // p->f();
  24.         p->test();
  25. }
上面这个形式就是:在基类里面的成员函数内调用子类的虚函数。是框架编程的一种很好方式。
(基类里面调用成员函数,默认是通过this指针,所以通过虚函数表就找到真实函数入口地址了)

另注:这里是指的普通成员函数,构造函数和析构函数内部调用虚函数,编译器规定都是调用本类的对应虚函数,否则会次序混乱而产生错误(分析:必须构造,才有对象,然后才能建立虚函数机制(对象实体的虚函数指针指向虚函数表);次序上析构基类时候,继承类已经释放,此时若调用子类虚函数,肯定错误)。

在c++里 构造和析构往往是有特殊身份的

阅读(3647) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

scq2099yt2013-05-03 18:39:53

如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。这句话有问题吧

Aquester2012-08-21 22:51:01

99%的情况,被子类重写的虚拟函数,在子类中都可定义为private,这也是最科学的,代码应当严谨,尊守最小化原则。如果一个虚拟函数是子类对象直接调用,则要考虑合理性了。