<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">首先提出几个问题:</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1、怎么获得数据成员的偏移量?</span>
2、如果类中有虚函数,类的布局是怎么样?vptr是放在对象内存的开始处还是结尾处,还是什么地方?(当然具体的编译器实现不同)
在这里在vs2010上进行几个简单的测试
测试例子1
Point3d.h文件
#pragma once
class Point3d
{
public:
Point3d(void);
~Point3d(void);
private:
public:
float x;
float y;
float z;
};
test.cpp文件
<pre name="code" class="cpp">#include <iostream>
#include <cstdio>
#include "Point3d.h"
using namespace std;
int main(void)
{
printf("%d, %d, %d\n", &Point3d::x, &Point3d::y, &Point3d::z);
cout << &Point3d::x << endl << &Point3d::y << endl << &Point3d::z << endl;
return 0;
}
输出结果:
0, 4, 8
1
1
1
上例中main函数中的&Point3d::x、&Point3d::y、&Point3d::z所求分别为x、y、z在类对象中的偏移量(offset)。偏移量的实现大多数编译器是通过整数来实现。这也表明指向类的数据成员的指针就是一个偏移量,并不是指向内存的具体地址。《深入理解c++对象模型》中讲到,对于偏移量,有些编译器会将数据成员的偏移量加上1。这样做的目的是为了区分一个“没有指向任何数据成员的”指针和一个指向“第一个数据成员的指针”(上面说了指向数据成员的指针也是偏移量,有些编译器实现为整数)。
但是可以看到vs2010中,并没有将偏移量增加1。所以说,使用printf的输出结果为0,4,8。而使用,cout的输出却都为1,这是因为iostream并没有重载成员指针类型。所以编译器在这里进行了转化,输出结果全为1。
如果类中有虚函数是,在vs2010中vptr的布局是怎么样的呢?
注意我只将Point3d类稍作修改,将它的析构函数声明为虚函数
#pragma once
class Point3d
{
public:
Point3d(void);
virtual ~Point3d(void);
private:
public:
float x;
float y;
float z;
};
<pre name="code" class="cpp">输出结果:
4, 8, 12
1
1
1
从这个例子可以看出,vs2010中vptr放在类对象的内存的开始处。所以三个数据成员的偏移量分别是4 、8 、12。