zoukankan      html  css  js  c++  java
  • C++ private访问限制

    了解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 << "	" << "m_nB: " << m_nB << "	" << "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 << "	" << "m_nB: " << m_nB << "	" << "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 << "	" << "m_nB: " << m_nB << "	" << "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 }

  • 相关阅读:
    ChinaUnionPay、Visa和MasterCard信用卡号验证
    使用Aspose.Cells 过程中用过的知识(转)
    在网页中回车默认按钮
    求素数算法
    通过jQuery的attr修改onclick(转)
    子页面js代码改变父页面iframe的大小(转)
    考虑线程安全但效率不高的单例C++代码
    Linux信号量摧毁/销毁
    WCF、WPF、Silverlight和区别(转)
    不考虑线程安全的初级单例C++代码
  • 原文地址:https://www.cnblogs.com/XavierJian/p/12912660.html
Copyright © 2011-2022 走看看