码迷,mamicode.com
首页 > 编程语言 > 详细

C++对象模型

时间:2015-08-25 18:39:58      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:

  本文主要对C++对象模型做一个简单总结。主要讨论以下几种情况下的C++对象的内存布局情况。

1)      单一的一般继承

2)      单一的虚拟继承

3)      多重继承

4)      重复多重继承

5)      钻石型的虚拟多重继承

虚函数

先简单介绍一下虚函数的机制。虚函数的主要作用是实现了多态的机制。对于多态,简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。从而让父类的指针有“多种形态”,这是一种泛型技术。

都知道虚函数是通过一张虚表来实现的,在这个表中主要是一个类的虚函数的地址列表。在有虚函数的类的实例中这个表就被分配在这个实例的内存中,它就像一个地图,指向实际应该调用的函数。为了保证取到虚函数表的有最高的性能,C++编译器一般会保证虚函数表的指针存放于对象实例中最前面的位置。这意味着我们可以通过对象实例的地址来获得这张虚函数表,从而遍历其中所有的函数指针,并调用。

下面给出一个实际的例子。

1 class Base {
2      public:
3             virtual void f() { cout << "Base::f" << endl; }
4             virtual void g() { cout << "Base::g" << endl; }
5             virtual void h() { cout << "Base::h" << endl; }
6  
7 };

我们可以通过Base的实例来得到虚函数表,使用如下代码:

 1 typedef void(*Fun)(void);
 2  
 3 Base b;
 4  
 5 Fun pFun = NULL;
 6  
 7 cout << "虚函数表指针的地址:" << (int*)(&b) << endl;
 8 cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;
 9  
10 // Invoke the first virtual function
11 pFun = (Fun)*((int*)*(int*)(&b));
12 pFun();

运行结果如下:

技术分享

我们强行把&b转成int *,取得虚函数表指针的地址,然后再次取址就得到第一个虚函数的地址了,即Base::f()。同样的,我们如果要调用Base::g()和Base::h(),可以使用如下代码:

1 (Fun)*((int*)*(int*)(&b)+0);  // Base::f()
2 (Fun)*((int*)*(int*)(&b)+1);  // Base::g()
3 (Fun)*((int*)*(int*)(&b)+2);  // Base::h()

下图可以帮助理解:

技术分享

注意:上面这个图中,虚函数表的最后有一个点,这个是虚函数表的结束点。这个值在不同的编译器下是不同的。在win8.1+vs2013中,这个值是NULL。在Ubuntu 14.04+GCC4.8.2中,如果这个值为1,表示还有下一个虚函数表(多重继承),如果值是0,则表示是最后一个虚函数表。

 (未完待续)

C++对象模型

标签:

原文地址:http://www.cnblogs.com/codinglol/p/4757947.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!