时间:2021-04-22 09:14:32 | 栏目:C代码 | 点击:次
类的对象不能直接访问类声明的私有成员变量,否则破坏了信息隐藏的目的。
在C++中,为了防止某些数据成员或成员函数从外部被直接访问,可以将它们声明为private,这样编译器会阻止任何来自外部非友元的直接访问。
私有成员变量的常用访问方法如下:
(1)通过公共函数为私有成员赋值
#include <iostream> using namespace std; class Test { private: int x, y; public: void setX(int a) { x=a; } void setY(int b) { y=b; } void print(void) { cout<<"x="<<x<<'\t'<<"y="<<y<<endl; } } ; int main() { Test p1; p1.setX(1); p1.setY(9); p1.print( ); return 0; }
(2)利用指针访问私有数据成员
#include <iostream> using namespace std; class Test { private: int x,y; public: void setX(int a) { x=a; } void setY(int b) { y=b; } void getXY(int *px, int *py) { *px=x; //提取x,y值 *py=y; } }; int main() { Test p1; p1.setX(1); p1.setY(9); int a,b; p1.getXY(&a,&b); //将 a=x, b=y cout<<a<<'\t'<<b<<endl; return 0; }
(3)利用函数访问私有数据成员
#include <iostream> using namespace std; class Test { private: int x,y; public: void setX(int a) { x=a; } void setY(int b) { y=b; } int getX(void) { return x; //返回x值 } int getY(void) { return y; //返回y值 } }; int main() { Test p1; p1.setX(1); p1.setY(9); int a,b; a=p1.getX( ); b=p1.getY(); cout<<a<<'\t'<<b<<endl; return 0; }
(4)利用引用访问私有数据成员
#include <iostream> using namespace std; class Test { private: int x,y; public: void setX(int a) { x=a; } void setY(int b) { y=b; } void getXY(int &px, int &py) //引用 { px=x; //提取x,y值 py=y; } }; int main() { Test p1,p2; p1.setX(1); p1.setY(9); int a,b; p1.getXY(a, b); //将 a=x, b=y cout<<a<<'\t'<<b<<endl; return 0; }
原则上,C++类中私有变量不允许在类之外的其他任何地方访问,一般来说功能完善的类都会提供get,set方法来操作类属性值,但如果没有get、set方法都没有提供,比如使用的是第三方提供的.o(或者动态库)来进行开发的,并且实际应用中我们确确实实需要改变其中某个对象的一个私有参数,有没有什么办法呢?我们知道,一个进程有程序段和数据段,如果我们知道了对象的数据空间,那么得到该对象的成员变量值也就很简单了,而实际上,对象数据段的首地址其实就是对象地址,以例子说明:
class A { public: int i; bool setJ(int _j){j = _j;}; int getJ() const {return j;}; private: int j; }; int main() { A a; printf("a's address is %u.n",&a); // 打印对象a的地址 printf("a.i's address is %u.n",(&(a.i))); // 打印对象a的成员变量i的地址 }
执行上面程序,可以看到结果,两个值时一样的,也就是说明对象地址就是第一个成员变量的地址。
我们知道,C++编译器将数据和程序段分开,所有的类变量会按照声明顺序依次存入数据段,所以,如果知道了第一个变量的地址,那么后面的地址也就依次累加即可逐一求出了。有了变量地址,那么也就可以对它的值进行修改了。还是以上面的例子来说明,一下程序编写了如何更改类成员b的值:
int main() { A a; a.setJ(2); printf("before modified:the member j of a is %d.n",a.getJ()); // 打印j的值。 int *p = (int *)(int(&a) + sizeof(a.i)); *p = 10; printf("after modified:the member j of a is %d.n",a.getJ()); // 打印j的值。 }
可以得出此时j成员变量的值由2变成10了。
总结:直接对地址空间操作,请小心为妙。。。
此外,另附一篇与此类似的文章,也很有启发性。
分析程序员和黑客的区别
题目:
设有如下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; }
结论:
程序员习惯于遵循既有的限制来增加既有的东西。
黑客习惯于利用既有的东西来打破既有的限制。