赞
踩
C++中有个特殊指针类型,就是指向数据成员的指针。这个数据成员的指针是可以提取出来的。如:
class Whatever {
public:
int x;
int z;
};
int Whatever::*mp;
mp = &Whatever::x;
如果数据的访问权限是private,则这样不可以。但可以通过模板的办法挑出来:
class Whatever {
int x;
int z;
};
template <class M, typename T, T M::*mp>
class Savein{
public:
static void init() { x=mp; }
static T M::*x;
};
template class Savein<Whatever , int, &Whatever ::x>;
template<> int Whatever::* Savein<Whatever, int, &Whatever::x>::x;
这里必须通过template语法显式声明Savein<Whatever, int, &Whatever::x>这个类。显式声明可以避免访问权限问题。如果没有用这个语法显式实例化这个类,直接用Savein<Whatever , int, &Whatever ::x>仍会碰到访问权限的问题。这样做是妥当的,因为数据成员默认都是private的,如果模板不接受指向private的数据成员的指针,这个语言也就没有这种功能了。
这一步过关之后,可以通过Whatever类的对象或指针和拣出来这个x来访问类的私有数据了,这时已经是运行期问题了。运行期不受访问权限的影响。这也是提取指向数据成员的指针的目的。
Whatever w;
Savein<Whatever, int, &Whatever::x>::init();
w.*Savein<Whatever, int, &Whatever::x>::x =3;
当然这还是累。能不能把Savein的类变量挪到外面来呢?
static unsigned int offset;
template <class M, typename T, T M::*mp>
class Saveout{
public:
static void init() { reinterpret_cast<T M::*&>(offset)=mp; }
};
template class Saveout<Whatever , int, &Whatever ::x>;
offset对应原来的类变量x。放到外面后offset不能带模板参数了,所以就让它成为整数值了。指向数据成员的指针概念上虽然复杂,实际内容不过是个记录偏移量的小整数。当然还是需要从mp赋值,但不能从mp转换。指向数据成员的指针,除了转换指向其它数据成员的指针,不能转换成别的类型。所以只能从左边想办法。转城右边类型的引用。这是C++特有的左值强制类型转换。
使用时这个offset再重新转换成数据成员的指针:
Whatever w;
Saveout<Whatever, int, &Whatever::x>::init();
w.*(int Whatever::*&)offset =3;
最后,因为offset 已经是整数类型了,可以对它进行调整,从而运行期访问其他数据成员。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。