C++对象模型——指向Data Members的指针(Pointer to Data Members)(第三章)

3.6 指向Data Members的指针(Pointer to Data Members)

    指向data members的指针,是一个有点神秘但颇有用处的语言特性,特别是如果需要详细调查 class members的底层布局的话,这样的调用可以决定vptr是放在 class 的起始位置或是尾端.另一个用途,可用来决定 class 中的access sections的次序.
    考虑下面的Point3d声明,其中有一个 virtual function,一个 static data member,以及三个坐标值:
class Point3d {
public:
	virtual ~Point3d();
protected:
	static Point3d origin;
	float x, y, z;
};
每一个Point3d class object含有三个坐标值,依次为x,y,z,以及一个vptr.至于 static data member origin,将被放在 class object之外,唯一可能因编译器不同而不同的是vptr的位置.C++ Standard允许vptr被放在对象中的任何位置:在起始位置,在尾端,或是在members之间.然而实际上,所欲编译器不是把vptr放在对象的头部,就是放在对象的尾部.
    那么,取某个坐标成员的地址,代表什么意思?例如,以下操作所得到的值代表什么:
& Point3d::z;
    上述操作将 得到z坐标在 class object中的偏移量(offset),最低限度其值将是x和y的大小总和,因为C++语言要求同一个access level中的members的排列次序应该和声明次序相同.
    (因为是2000年写的书,编译器比较早, 有点疑惑)现在在g++4.8上如下打印地址:
cout << "&Point3d::_x = " << &Point3d::_x << endl;
cout << "&Point3d::_y = " << &Point3d::_y << endl;
cout << "&Point3d::_z = " << &Point3d::_z << endl;
cout << "sizeof(Point3d) = " << sizeof(Point3d) << endl;
得到如下结果:

    如何区分一个"没有指向任何data member"的指针和一个指向"第一个data member"的指针?考虑这样的例子:
float Point3d::*p1 = 0;
float Point3d::*p2 = &Point3d::x;
if (p1 == p2) {
	cout << "p1 & p2 contain the same value --";
	cout << "they must address the same member!" << endl;
}
为了区分p1和p2,每一个真正的member offset值都被加1.因此,不论编译器或使用者都必须记住,在真正使用该值以指出一个member之前,请先减掉1.
    认识"指向data members的指针"之后,要解释:
&Point3d::z;
&origin.z;
之间的差异,就非常明确了.鉴于 "取一个nonstatic data member的地址,将会得到它在class中的offset",取一个"绑定于真正class object上的data member"的地址,将会得到该member在内存中的真正地址.
&orgin.z
    所得结果减z的偏移值(相当于origin起始地址),并加1,就会得到origin起始地址.上一行的返回值类型应该是:
float *
    而不是
float Point3d::*
    结果如下所示:

"指向Members的指针"的效率问题

    下面的测试,了解使用"指向members的指针"所带来的影响,第一个例子是要取得一个"已绑定的member"的地址:
float *ax = *pA._x;
    然后进行赋值操作,如下:
*bx = *ax - *bz;
*by = *ay + *bx;
*bz = *az + *by;
第二个例子则是针对三个members,取得"指向data member的指针"的地址:
float Point3d::*ax = &Point3d::x;
    而赋值操作,都是使用"指向data member的指针"语法,把数值绑定到对象pA和pB中:
pB.*bx = pA.*ax - pB.*bz;
pB.*by = pA.*ay + pB.*bx;
pB.*bz = pA.*az + pB.*by;
测试结果如下所示:
    
    ....(与之前没有太大差别)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值