了解C++的同学都很清楚,C++有3个访问控制符,提供了对数据的封装,分别是public、protected与private。
private算是对数据保护得最严实的控制符了,一般都会说到private成员只能被类本身的成员函数以及类的友元访问,其他函数需要访问时,
大多数会封装一个public的set和get方法进行访问,或者 返回指针与引用也是可以的,但并不推荐,毕竟这样不利于封装的特性,
当然,下面介绍的方法是进行讨论使用其他方式突破private的访问限制,一般情况下也不会使用。
那么先从代码开始吧。
1 #include <iostream> 2 3 using namespace std; 4 class TestClass 5 { 6 public: 7 TestClass() : m_nA(1), m_nB(2), m_nC(3) {}; 8 ~TestClass() {}; 9 void PrintValue() 10 { 11 cout << "m_nA: " << m_nA << "\t" << "m_nB: " << m_nB << "\t" << "m_nC: " 12 << m_nC << endl; 13 } 14 private: 15 int m_nA; 16 int m_nB; 17 int m_nC; 18 }; 19 int main() 20 { 21 TestClass Test; 22 Test.PrintValue(); 23 24 cout << "---------------------------------------------------" << endl; 25 26 int nValue = 7; 27 int* ptr = (int*)(&Test); 28 *(ptr++) = nValue++; 29 *(ptr++) = nValue++; 30 *(ptr++) = nValue++; 31 32 Test.PrintValue(); 33 34 return 0; 35 }
当声明了一个Test对像时,那么系统将会开辟一段连续的空间,此对象将会有如下的内存布局,如何正确的访问,需要考虑到字节的对齐。
有了内存空间,当然可以使用指针进行访问,那么强行对此内存地址赋值即可。
27~30行的操作就是如此。
简单的总结来说,访问说明信息通常是在编译期间消失,在程序运行期间,对象变成了一个存储区域,别无他物,
因此,如果有人想破坏这些规则并且直接访问内存中的数据,是很容易的(存在大量的数据,继承时,使用此方法精确的更改数据内容就会变得非常困难),
C++并不能防止这种不明智的操作,毕竟C++关注的焦点是抽象。
那么除此之外还有其他方法吗?
答案是有的
比如声明另一个classB,只需要在classB中,把classA的private的访问控制符更改为public。
此时,相应的对象B与对象A的内存布局是一致的,只是访问限制不同,所以可以利用访问对象B的规则去访问对象A。
一个指向B对象的指针实际指向了一个A对象,对B中public成员变量的访问实际上是对A对象中private成员变量的访问。
1 #include <iostream> 2 3 using namespace std; 4 class TestClass 5 { 6 public: 7 TestClass() : m_nA(1), m_nB(2), m_nC(3) {}; 8 ~TestClass() {}; 9 void PrintValue() 10 { 11 cout << "m_nA: " << m_nA << "\t" << "m_nB: " << m_nB << "\t" << "m_nC: " 12 << m_nC << endl; 13 } 14 private: 15 int m_nA; 16 int m_nB; 17 int m_nC; 18 }; 19 20 class TestClassB 21 { 22 public: 23 TestClassB() : m_nA(11), m_nB(22), m_nC(33) {}; 24 ~TestClassB() {}; 25 void PrintValue() 26 { 27 cout << "m_nA: " << m_nA << "\t" << "m_nB: " << m_nB << "\t" << "m_nC: " 28 << m_nC << endl; 29 } 30 public: 31 int m_nA; 32 int m_nB; 33 int m_nC; 34 }; 35 36 int main() 37 { 38 TestClass a; 39 TestClassB* b = (TestClassB*)&a; 40 a.PrintValue(); 41 b->m_nA = 6; 42 b->m_nB = 9; 43 cout << "m_nA:" << b->m_nA << endl; 44 cout << "m_nB:" << b->m_nB << endl; 45 a.PrintValue(); 46 return 0; 47 }