C++突破private访问权限的黑科技

    xiaoxiao2024-04-22  189

    昨天,有位同事抛出了一个问题:

    一个class内有一个private属性的struct类型,然后他想做的事情是,在继承该class的子类中复用这个类型,但是由于该类似的private属性,编译是不通过的。

    因此就引入了一个问题:如何突破class的private属性限制——试图破坏class的封装性,有点“逆天而行”的感觉。

    查了一下,方法确实是有的。

    假设有以下类:

    m_nPrivate class X { private: int m_nPrivate; ​ public: X() : m_nPrivate(1) {} ​ template<typename T> void Func(const T &t) {} ​ const int GetValue() { return m_nPrivate; } };

    方法1:使用指针

    void *p = &x; // 获取类的起始地址,其实也就是m_nPrivate数据成员的地址 int *n = (int *)p; ​ int tmp = 2; *n = tmp; // 改写其值cout << x.GetValue() << endl; // 输出为2

    这种方法的缺点:计算偏移量是个麻烦的事情,涉及到内存对齐、编译器版本等,可移植性低,而且这种方法只能访问成员变量,却不能达到“使用private内置类型”的目的。

    方法2:使用宏

    在类X的定义前,加一句:

    #define private public

    该方法可以欺骗编译器,让它把“private”当作“public”。

    然而它有两个违背标准的行为:

    1)#define 保留字是非法的

    2)违反了唯一定义规则(ODR,One Definition Rule),然而类的底层内存布局没改变,故可行

    方法3:使用指针类型转换——偷天换日

    m_nNotPrivate // 同X的内存布局,将变量or类型定义改为public class Y { public: int m_nNotPrivate; }; ​ void Func(X* xPtr) { (reinterpret_cast<Y*>(xPtr))->m_nNotPrivate = 2; }

    首先我们将X类型的指针转换为Y类型的指针,在编译器看来,我们访问的是Y类型的public成员m_nNotPrivate,因此编译通过,然而事实上该指针是X类型的,由于Y跟X的内存布局是完全一样,因此访问Y的m_nNotPrivate成员实际上也就是在访问X的m_nPrivate成员。

    类似的方法就是,在Y中增加一个非虚成员函数,该函数用来返回m_nPrivate的地址。

    方法4:添加友元声明

    类似以上方法,不过是通过添加友元声明来访问的~

    方法5:利用模版合法钻空子

    如果X中存在一个成员模版,那么可以这样子:

    namespace { struct Y{}; } ​ template<> void X::Func(const Y&) //特化 { m_nPrivate = 2; } ​ void Test() { X x; cout << x.GetValue() << endl; ​ x.Func(Y()); cout << x.GetValue() << endl; }

    这种方法利用了X具有一个成员模板的事实,通过特化函数模版,来打入敌人内部。代码完全符合标准,标准也确保这种行为会按照编码者的意图行事。boost和loki中大量运用此手法。

    以上方法参考:http://blog.csdn.net/chenyu2202863/article/details/5043106

    转载请注明原文地址: https://ju.6miu.com/read-1288267.html
    最新回复(0)