原则上,C++类中私有变量不允许在类之外的其他任何地方访问,一般来说功能完善的类都会提供get,set方法来操作类属性值,还有是是通过友元访问。但是!但如果没有get、set方法都没有提供,也没有定义友元,比如使用的是第三方提供的.o(或者动态库)来进行开发的,并且实际应用中我们确确实实需要改变其中某个对象的一个私有参数,有没有什么办法呢?还有一种比较文艺青年的方法,我们知道,一个进程有程序段和数据段,如果我们知道了对象的数据空间,那么得到该对象的成员变量值也很简单了,而实际上,对象数据段的首地址其实是对象地址,以例子说明:
方法1:普通青年
友元方法:
#include<iostream.h>
class A { int t; public: A() { t=2002;//在构造函数中初始化成员变量t
} friend class B;//声明友元类classB
};
class B { public: A a; int sum() { return a.t+1500;//友员class B访问class A中的私有成员变量t
} };
void main() { B b; cout<<b.sum()<<endl; }
方法2:文艺青年
内存地址操作法
我们知道,C++编译器将数据和程序段分开,所有的类变量会按照声明顺序依次存入数据段,所以,如果知道了第一个变量的地址,那么后面的地址也依次累加即可逐一求出了。有了变量地址,那么也可以对它的值进行修改了。还是以上面的例子来说明,一下程序编写了如何更改类成员b的值:
#include <iostream> #include <string> using namespace std;
class center { public: void setX(float _x){x=_x;} void setY(float _y){y=_y;} void setMeanValue(float avg){meanValue=avg;} float getX(){return x;} float getY(){return y;} float getMeanValue(){return meanValue;} center():x(0.0),y(0.0),meanValue(0.0){} private: float x; float y; float meanValue; };
int main() { center A; //普通青年的赋值方法; A.setX(1.0); A.setY(4.0); A.setMeanValue(13.0); cout<<A.getX()<<" "<<A.getY()<<" "<<A.getMeanValue()<<endl; //文艺青年的赋值方法; //*((float*)&A):将center对象A的内存空间强制类型转化为用int*指向的内存空间,访问该内存 float tmp = *((float*)&A); cout<<tmp<<endl;//输出A.x的值 tmp = *((float*)&A + 1); cout<<tmp<<endl;//输出A.y的值 *((float*)&A + 2)=2;//修改A.meanValue的值 cout<<A.getMeanValue()<<endl; }
你也可以通过友元的内存地址来操作,即通过class B 的内存地址访问 class A的私有成员。
此外,另附一篇与此类似的文章,也很有启发性。
分析程序员和黑客的区别
题目:
设有如下C++类
class A { int value; public: A(int n = 0) : value(n) {} int GetValue() { return value; } };
请使用某种方式来在类的外部改变私有成员A::value的值。
程序员的可能做法:
class A { int value; public: A(int n = 0) : value(n) {} int GetValue() { return value; } void SetValue(int n) { value = n; } }; void f() { A a; a.SetValue(5); }
黑客的可能做法:
void f() { A a; *((int *)&a) = 5; }
结论:
程序员习惯于遵循既有的限制来增加既有的东西。
黑客习惯于利用既有的东西来打破既有的限制。