如何用C++偷私有變量

最近在開源代碼中發(fā)現(xiàn)了一種不修改代碼的情況下, 訪問庫中的類的私有成員變量的方法. 我們知道, 一個類的成員變量設(shè)置成private, 外部函數(shù)一般通過友元才能訪問. 但是庫已經(jīng)寫好了, 在不修改庫的代碼, 為其添加友元的情況下, 也可以使用一些特殊技巧訪問類的私有成員.
為了介紹這個方法, 首先介紹一些C++中的特性, 如下.

指向成員的指針(pointer to member variable)

C++中可以定義指向類成員變量的指針類型. 這個成員變量可以不是static的.

代碼來自此鏈接: stackoverflow/670734

#include <iostream>
using namespace std;
class Car {
    public:
    int speed;
};

int main() {
    //定義一個指向成員speed的指針, 用成員的地址初始化.
    int Car::*pSpeed = &Car::speed;

    Car c1;
    c1.speed = 1;       // direct access
    cout << "speed is " << c1.speed << endl;
    
    //已經(jīng)有一個類的時候, 可以通過這個指針來訪問類的成員.對于任意不同的類都可
    //以這么干.
    c1.*pSpeed = 2;     // access via pointer to member
    cout << "speed is " << c1.speed << endl;
    return 0;
}

從上面的帶注釋的例子可以看出, 這里的指針和常見的表示具體地址的指針是不一樣的. 這樣, 我們要訪問一個類的成員變量, 除了通過"."訪問, 還可以定義指針來訪問.

模板顯式實例化(template Explicit instantiation)

我們知道, 對于類模板來說, 我們提供模板參數(shù)可以實例化一個模板類. 除了這種方法以外, 模板還可以使用顯式實例化, 在顯式實例化的時候, 會忽略參數(shù)的private屬性.

所以到此, 訪問的方法就比較清晰了. 我們可以定義一個指針來指向類的私有成員, 但是由于成員是私有的, 直接賦值不會成功, 所以我們可以利用模板參數(shù)的方式完成賦值, 通過顯式實例化來忽略private修飾符.

一個訪問私有成員的例子

介紹完了基礎(chǔ)知識, 接下來看一個例子. 我們在例子中定義了一個類FortKnox, 里面有一個private成員 value. 這個類是別人寫的, 設(shè)置private為了讓別人不能直接訪問, 并且編譯到了動態(tài)庫里面. 但是利用上面介紹的方法, 我們可以偷偷使用類里面的private變量.

代碼改編自stackoverflow/15110526

#include<iostream>
using namespace std;

typedef int value_type;
//定義了一個類,里面有一個private成員,我們不希望別人直接訪問
struct FortKnox {
    FortKnox() : value(0) {}
private:
    value_type value;
};

//這是一個指向類的成員變量的指針類型
typedef value_type FortKnox::* stolen_mem_ptr;

//模板定義一個友元函數(shù),返回指向類的成員變量的指針.
template<stolen_mem_ptr MemPtr>
struct Robber {
    friend stolen_mem_ptr steal() {
        return MemPtr;
    }
};
//模板顯式初始化, 可以忽略private修飾符, 這樣我們的友元函數(shù)就可以
//獲得指向成員的指針,并且忽略了private
template struct Robber<&FortKnox::value>;
stolen_mem_ptr steal();

int main() {
    FortKnox f;
    //返回指向成員的指針,忽略了private修飾符
    auto accessor = steal();
    //訪問私有成員
    cout<<f.*accessor<<endl;
    f.*accessor=1;
    cout<<f.*accessor<<endl;
    return 0;
}

總結(jié)

這個特性平時應(yīng)該比較少用到, 既然碰到了, 就記錄一下.

相關(guān)文獻(xiàn)

[1] http://bloglitb.blogspot.de/2011/12/access-to-private-members-safer.html

[2] http://stackoverflow.com/questions/670734/c-pointer-to-class-data-member

[3] http://stackoverflow.com/questions/15110526/allowing-access-to-private-members


原始鏈接:yiwenshao.github.io/2017/01/16/如何用C-偷私有變量/
文章作者:Yiwen Shao
許可協(xié)議:** Attribution-NonCommercial 4.0
轉(zhuǎn)載請保留以上信息, 謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,537評論 1 51
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 重新系統(tǒng)學(xué)習(xí)下C++;但是還是少了好多知識點;socket;unix;stl;boost等; C++ 教程 | 菜...
    kakukeme閱讀 20,030評論 0 50
  • 第一天 一.內(nèi)聯(lián)函數(shù)(inline) 函數(shù)調(diào)用的時候需要建立棧內(nèi)存環(huán)境,進(jìn)行參數(shù)傳遞,并產(chǎn)生程序執(zhí)行轉(zhuǎn)移,這些工作...
    陳果123閱讀 1,145評論 0 1
  • 1 我將注意力分成兩份,大小不一,每一份都代表著一個自我。于是我有兩個我。 那么,我的安排是:一個抬頭看方向,一個...
    Firewinter閱讀 332評論 0 1