day4 4.6指针突破访问权限

我们都知道,C++ 不允许通过对象来访问 private、protected 属性的成员变量;C++面向对象中有一大特性就是封装,使用不同的访问控制符来控制外界对其的访问权限。

#include<iostream>
using namespace std;
class A{
    private://私有
        int mPrivate;
        int nPrivate;
    public:
        A():mPrivate(1),nPrivate(2){};
        template<typename T> void func(const T &t){}
        const int GetValueN(){
            return nPrivate;
    }
};

不过 C++ 的这种限制仅仅是语法层面的,通过某种“蹩脚”的方法,我们能够突破访问权限的限制,访问到 private、protected 属性的成员变量,赋予我们这种“特异功能”的,正是强大而又灵活的指针(Pointer);

可以通过以下方法突破对private成员的访问权限
1)操作指针修改内存数据,根据偏移(推荐)
在对象的内存模型中,成员变量和对象的开头位置会有一定的距离;和struct结构体中的数据成员偏移量(offset)是一个概念;

一旦知道了对象的起始地址,再加上偏移就能够求得成员变量的地址,知道了成员变量的地址和类型,也就能够轻而易举地知道它的值;

当通过对象指针访问成员变量时,编译器实际上也是使用这种方式来取得它的值;

#include<iostream>
#include "dome.h"
using namespace std;
int main(){
    A obj=A();
    int temp=3;
    int *ptr=(int*)(&obj);
    *(ptr+1)=temp;//实际上就是根据偏移量
    cout<<"nPrivate="<<obj.GetValueN()<<endl;
   //nPrivate=3
    return 0;
}

2)使用友元声明(可以是友元函数或者友元类)

#include<iostream>
using namespace std;
class A{
    private:
        friend void Jack(A &);//友元函数
        int mPrivate;
        int nPrivate;
    public:
        A():mPrivate(1),nPrivate(2){}
        template<typename T> void fun(const T &t){}
        const int GetValueN(){
            return nPrivate;
        }
};
void Jack(A &a){
    a.nPrivate=3;
}
int main(){
    A obj=A();
    Jack(obj);
    cout<<"nPrivate="<<obj.GetValueN()<<endl;
    return 0;
}

3)使用模板
类A中定义了一个模板函数func(),在类外加一个模板函数,导致模板推演的过程中多出一个自己写的并且加入了备选组中,相当于多了一个重载。类外函数的参数是在匿名空间中定义的特定类型,所以避免扰乱原本该函数的功能。

#include<iostream>
using namespace std;
class A{
    private:
        int mPrivate;
        int nPrivate;
    public:
        A():mPrivate(1),nPrivate(2){};
        template<typename T> void func(const T &t){}
        const int GetValueN(){
            return nPrivate;
    }
};
namespace {struct B{};}
template<> void A::func(const B&){
    nPrivate=3;
}
int main(){
    A obj;
    obj.func(B());
    cout<<"nPrivate="<<obj.GetValueN()<<endl;
    return 0;
}

4)使用宏,缺点是造成二义性

#define private public

5)利用指针修改私有成员

#include<iostream>
using namespace  std;
class A{
    public:
        A():i(1){}
        void print(){
            cout<<"A::i="<<i<<endl;
            }
    private:
        const int i;
};
int main(){
    A a;
    int* p=(int*)&a;   //突破编译器防线
    a.print();
    *p=30;            //修改a对象私有成员的值
    a.print();        
    return 0;
}

C++ 的成员访问权限仅仅是语法层面上的,是指访问权限仅对取成员运算符.和->起作用,而无法防止直接通过指针来访问;
参考博客

发布了94 篇原创文章 · 获赞 66 · 访问量 5480

猜你喜欢

转载自blog.csdn.net/qq_44861675/article/details/105112626