整理第三章最后的部分内容,关于数据成员指针的,之前竟然没听过类数据成员指针一说,果然路漫漫其修远兮啊。
注:以下例子和图片来源于原书。
1. 数据成员指针是指指向类数据成员的指针,其内容为对应数据成员在类对象中的偏移量,类型为A::*,例如,如下类:
class Point3d {
public:
virtual ~Point3d();
protected:
static Point3d origin;
float x, y, z;
};
以下操作: &Point3d::z,将得到一个偏移值,其值最小为x和y大小的总和,或者是加上一个指针大小,这是因为类Point3d中存在虚函数,对应的类对象中就要有一个指向虚函数表的指针,该指针在类对象布局中,可能放在最前端,此时x,y,z的偏移分别为:4,8,12,也可能放在最末端,此时x,y,z的偏移分别为:0,4,8,然而实际取出来的值却并非是这样,这个值总是比实际大一,即1,5,9类似(在VS2015中测试并没有大一,猜测是编译器做了优化),之所以需要大一,是为了区分一个没有指向任何数据成员的指针和一个指向了第一个数据成员的指针,例如:
float Point3d::*p1 = 0;
float Point3d::*p2 = &Point3d::x;
注意取非静态数据成员的地址(静态数据成员不属于具体的类对象,故没有偏移量一说)和取绑定与真正类对象身上的数据成员的地址的区别,Point3d origin; &origin.z类型为float*而不是Point3d::*,相应的静态成员的类型也为float*。
指向数据成员的指针的使用方法:
float Point3d::*p2 = &Point3d::x;
Point3d point;
point.*p2 = 1//等价于point.x = 1
Point3d* p3d = &point;
p3d->*p2 = 2;//等价于p3d->x = 2
2. 多重继承的情况下,将第二个(或者后继)基类指针与一个和子类对象绑定的数据成员结合起来时,情况会变得复杂,例如:
此种情况下,必须要考虑Base1存在导致的Base2的偏移,注意判零:func1(bmp ? bmp + sizeof(Base1) : 0, pd );
第三章的内容整理完成,之后会继续整理第四章的内容。