如何突破類private的訪問控制限制

如何突破類private的訪問控制限制

類的訪問控制權限如下:

訪問 public protected private
同一個類 yes yes yes
派生類 yes yes no
外部及外部類類 yes no no

接下來主要說一下外部函數及外部類幾種突破private訪問權限的方法。

調用公共成員函數

#include <iostream>
using namespace std;
class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    int geta(){
        return a;
    }
    void seta(int x){
        a=x;
    }
    int getb(){
        return b;
    }
    void setb(int x){
        b=x;
    }
    friend int setgetbx(X &,int x);
};
int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;
    s.seta(10);
    s.setb(10);
    cout<<"reset a="<<s.geta()<<endl;
    cout<<"reset b="<<s.getb()<<endl;
    return 0;
}

運行結果:
在這裏插入圖片描述

友元函數

友元函數一般放在類的開始或者結束位置,在類內聲明+friend關鍵字,在類外定義

#include <iostream>
using namespace std;

class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    int geta(){
        return a;
    }
    int getb(){
        return b;
    }
    friend int setgetbx(X & x,int temp);				// 類內聲明友元函數
};
int setgetbx(X & x,int temp){  							// 類外定義友元函數
    x.b+=temp;
    return x.b;
}
int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;

    int newb=setgetbx(s,5);								//調用友元函數
    cout<<"reset b="<<newb<<endl;
    cout<<"reset b="<<s.getb()<<endl;
    return 0;
}

運行結果:
在這裏插入圖片描述

使用 指針與引用訪問

#include <iostream>
using namespace std;
class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    int geta(){
        return a;
    }
    int getb(){
        return b;
    }
};

int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;
    int *ptr=(int *)(&s);                          		 // 類指針
    cout<<"init a="<<*ptr<<endl;
    cout<<"init b="<<*(ptr+1)<<endl;
    *ptr=5;												//指向a
    *(ptr+1)=5;											// 指向b
    cout<<"pointer reset a="<<s.geta()<<endl;
    cout<<"pointer reset b="<<s.getb()<<endl;
    return 0;
}

運行結果:
在這裏插入圖片描述
這裏需要注意,如果有虛函數的話,指針需要加+ *(ptr+1) *(ptr+2) 因爲虛函數表是類內第一個位置。

指針的類型裝換

#include <iostream>

using namespace std;

class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    int geta(){
        return a;
    }
    int getb(){
        return b;
    }
};

class Y
{
public:
    int a;			//與 X裏面a對應
	int b;			//與 X裏面b對應
};

void Func(X* xPtr)
{
	// reinterpret_cast 用於進行各種不同類型的指針之間、
	// 不同類型的引用之間以及指針和能容納指針的整數類型之間的轉換。
	(reinterpret_cast<Y*>(xPtr))->b = 2;
}

int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;
    Func(&s);
    Func(&s);
    //cout<<"reinterpret_cast reset a="<<s.geta()<<endl;
    cout<<"reinterpret_cast reset b="<<s.getb()<<endl;
    return 0;
}

下面結果爲類X與Y內存對齊的情況,即X與Y 裏面的成員變量x.a x.b的位置一一對應:
在這裏插入圖片描述
如果不對齊的話看下面一個實驗

#include <iostream>

using namespace std;

class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    int geta(){
        return a;
    }
    int getb(){
        return b;
    }
};

class Y
{
public:
	int b;
};

void Func(X* xPtr)
{
	// reinterpret_cast 用於進行各種不同類型的指針之間、
	// 不同類型的引用之間以及指針和能容納指針的整數類型之間的轉換。
	(reinterpret_cast<Y*>(xPtr))->b = 2;
}

int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;
    Func(&s);												//attention
    cout<<"reinterpret_cast reset a="<<s.geta()<<endl;
    cout<<"reinterpret_cast reset b="<<s.getb()<<endl;
    return 0;
}

此時修改Y的b 但是確實修改X裏面的a,這是因爲 Y的b 與X的啊 在類內具有相同的內存位置,歸根究低還是對指針與實際內存的操作:
在這裏插入圖片描述

利用模版合法

#include <iostream>

using namespace std;

class X {
private:
    int a;
    int b;
public:
    X(): a(3), b(4){}
    template<typename T>				//在X類內定義成員模板函數
	void Func(const T &t){}
    int geta(){
        return a;
    }
    int getb(){
        return b;
    }
};
class Y {}; 												//外部Y類
template<>
void X::Func(const Y&) //特化						//attention			
{
	a=2;
	b=8;
}
int main()
{
    X s=X();
    cout<<"init a="<<s.geta()<<endl;
    cout<<"init b="<<s.getb()<<endl;
    s.Func(Y());									//attention
    cout<<"template reset a="<<s.geta()<<endl;
    cout<<"template reset b="<<s.getb()<<endl;
    return 0;
}

運行結果:
這種方法利用了X具有一個成員模板的事實,通過特化函數模版,來打入敵人內部。代碼完全符合標準,標準也確保這種行爲會按照編碼者的意圖行事。boost和loki中大量運用此手法。
在這裏插入圖片描述
參考:http://www.luyixian.cn/news_show_37214.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章