女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

從技術實現的角度破壞封裝性直接訪問私有變量

CPP開發者 ? 來源:高性能架構探索 ? 2023-02-15 09:31 ? 次閱讀

C++教材的前幾章就介紹了其特性,即:C++是一門面向對象語言,具有封裝、繼承和多態三個特點。后來,隨著編碼的增多以及工作經驗的積累,對個概念的理解越來越深。編碼習慣也嚴格按照相應的規則,該封裝的時候進行封裝,該繼承的時候進行繼承,以使得編程思維從之前的面向過程逐步過渡到面向對象。

作為開發人員,遵循編程規則本來就無可厚非,但是如果大家都遵循規則難免會有創新或者技術進步。有時候,在做某件事或者看到某個實現方案的時候,想想為什么要這么做,有沒有更好的實現方案,這個編程或者做事習慣往往使得自己受益匪淺。

比如,我們都知道每個線程都有一個自己的棧,線程內的局部變量出了作用域就會被釋放,那么有沒有可能跨線程從另外一個線程去訪問該線程的局部變量呢?其實,問題不算難,我們只需要嘗試即可,但往往缺少的就是這種嘗試。對于C++三大特性中的封裝特性,如果直接訪問私有變量,則編譯器會報錯,那么有沒有其它方式可以訪問私有變量呢?

今天,不妨試著反其道而行,嘗試以其他方式破壞封裝性,直接訪問私有變量。

從一段代碼說起

代碼示例如下:

#include

classA{
public:
A()=default;
private:
intdata_=0;
};

intmain(){
Aa;
std::cout<

在gcc5.4下進行編譯,不出所料,編譯失敗,報錯如下:

test.cc:在函數‘intmain()’中:
test.cc:7:15:錯誤:‘int A::data_’是私有的
intdata_=0;

從報錯信息看,因為data_成員變量是私有的,而通過對象訪問私有成員變量是不被允許的,除了通過重新定義一個公共接口,在該接口內對data_進行訪問外,但是這種方式并沒有實現本文的目的即破壞封裝性,那么有沒有其它方式呢?

第一次嘗試

c++標準中有這樣一段描述:

The usual access checking rules do not apply to non-dependent names used to specify template arguments of the simple-template-id of the partial specialization. [ Note:The template arguments may be private types or objects that would normally not be accessible. Dependent names cannot be checked when declaring the partial specialization, but will be checked when substituting into the partial specialization. — end note ]

也就是說模板參數可以是某個類的私有類型,所以,我們可以借助此條標準繼續實現我們的目的,代碼如下:

#include

classA{
public:
A()=default;
private:
intdata_=0;
};

template
int&GetPrivateData(A&obj){
returnobj.*Member;
}

templateint&GetPrivateData<&A::data_>(A&);

intmain(){
Aobj;
GetPrivateData<&A::data>(obj);

return0;
}

在上述代碼中,定義了一個函數模板,其模板參數為int A::*Member,功能是返回類A中的成員變量,編譯后,報錯如下:

test.cc:在函數‘intmain()’中:
test.cc:7:15:錯誤:‘int A::data_’是私有的
intdata_=0;
^
test.cc:22:3:錯誤:在此上下文中
GetPrivateData<&A::data_>(obj);

看來此方式還是行不通,只能另想它法。

第二次嘗試

在上面的提示中,顯示不能直接訪問私有成員,標準提供了個方法,就是將需要訪問類私有成員的函數或者類聲明為friend。看到這塊,你可能會想,有了friend用得著你教?。

很快寫出如下這種代碼:

classA{
public:
A()=default;
private:
intdata_=0;

friendintAccess(constA&a){
returna.data_;
}
};

intmain(){
Aa;
Access(a);

return0;
}

無疑,上面這種代碼可以訪問私有成員,但缺點是需要更改類實現,下面將介紹一種方式,其在不修改類本身定義的情況下實現訪問私有成員變量。

本著大方向不變的原則,依然使用模板的方式訪問私有成員,而對于上節中提示的非法訪問私有成員,我也采用將對應函數聲明為friend的方式。

#include

classA{
public:
A()=default;
private:
intdata_=0;
};

template
classAccess{
public:
friendintGetPrivateData(A&obj){
returnobj.*Member;
}
};

templateclassAccess<&A::data_>;

intGetPrivateData(A&);


intmain(){
Aobj;
GetPrivateData(obj);

return0;
}

編譯 & 運行,OK!!!

另辟蹊徑

在上一節實現中,使用了friend進行訪問控制,所以在考慮有沒有不使用friend的方式,于是在網上進行搜索查閱,如下:

classA{
public:
A(intnum):data_(num){};
private:
intdata_=0;
};

template
classAccess{
public:
inlinestaticPtrTypeptr;
};

template
structPtrTaker{
structTransferer{
Transferer(){
Access::ptr=T;
}
};
inlinestaticTransferertr;
};

templateclassPtrTaker<&A::data_>;//顯示實例化

intmain(){
Aa{10};

intb=a.*Access::ptr;

return0;
}

說真的,看到這種實現方式的時候,一臉懵逼,尤其是對模板用的不多的情況下,閱讀這短短幾十行代碼用了一天時間,其間也跟@Chunel駿哥哥一起討論,奈何太挫了,只能硬著頭皮自己研究,也跟群里的大佬們一起討論了下,再結合自己的理解,分析下這塊:

1、因為用到了inline 變量以及模板參數為auto,所以上述代碼在cpp17上才可以運行。

2、以&A::data_作為模板參數,對類模板PtrTaker進行顯示實例化,在顯示實例化的時候,雖然不創建對象,但是對于其中存在的靜態變量依然會進行初始化。因此會調用Transferer類的構造函數,從而對Access::ptr進行初始化

看上述代碼的時候,一開始卡在了a.*Access::ptr這部分,后來經過跟其他技術大佬進行溝通,對這部分可以進行拆分簡化:

?p = Access::ptr;

?a.*p

看了下面的代碼示例,相信能便于理解:

classData{
public:
intnum_=0;
};

intmain(){
intData::*ptr=&Data::num_;

Datadata;
data.*ptr=10;

return0;
}

好了,我們接著進行討論。

在使用對象訪問成員的時候,其地址實際上分為兩部分的,以a.data_為例(此處忽略訪問控制權限),一部分是a的this指針,另一部分是data_成員在A結構里的偏移量,這個偏移量存儲在&A::data_中。在上面的代碼中,這個偏移量存儲在靜態數據ptr里了,即上面提到的Access::ptr。

所以,a.*p相當于如下:

intA::*p=&A::data_;
intoffset=*(longlong*)&p;
intdata=*(int*)((char*)&a+offset);

好了,截止為此,通過模板方式訪問類私有成員的討論結束了。

可能有人會有疑問,如果類有多個成員變量,又該如何訪問呢,方式類似,代碼如下:

#include
#include

classA{
public:
A(intnum,std::stringv):data_(num),value_(v){};
private:
intdata_=0;
std::stringvalue_;
};

template
classAccess{
public:
inlinestatictypenameTag::typeptr;
};

template
structPtrTaker{
structTransferer{
Transferer(){
Access::ptr=V;
}
};
inlinestaticTransferertr;
};

structTag1{
usingtype=intA::*;
};

structTag2{
usingtype=std::stringA::*;
};

templateclassPtrTaker;//顯示實例化
templateclassPtrTaker;//顯示實例化

intmain(){
Aa{0,"abc"};

std::cout<::ptr;
}






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7628

    瀏覽量

    140079
  • 編譯器
    +關注

    關注

    1

    文章

    1653

    瀏覽量

    49815
  • C++語言
    +關注

    關注

    0

    文章

    147

    瀏覽量

    7213
  • gcc編譯器
    +關注

    關注

    0

    文章

    78

    瀏覽量

    3629

原文標題:訪問私有成員——從技術實現的角度破壞"封裝" 性

文章出處:【微信號:CPP開發者,微信公眾號:CPP開發者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    基于CXL的直接訪問高性能內存分解框架

    鑒于KAIST的HPC根源,將DirectCXL原型放在一起的研究人員專注于使用遠程直接內存訪問(RDMA)協議將CXL內存池與跨系統直接內存訪問進行比較。
    發表于 09-23 10:50 ?1540次閱讀

    CysecureTools如何直接訪問外部存儲設備內的密鑰呢?

    顯然不符合安全標準。 那么,如標題所示,CysecureTools應該如何直接訪問外部存儲設備內的密鑰呢?\"
    發表于 01-31 08:08

    Labview通過VXI總線直接訪問測量儀器內部寄存器

    VXI總線直接訪問測量儀器內部寄存器,從而在線獲取干涉儀的距離測量結果,從而與我的位移測量系統作比對。大家如果對激光干涉儀不了解不要緊,請告訴我如何通過VXI總線直接訪問測量儀器內部寄存器,有遇上類似情況的嗎? 本人對VXI及Labview了解不多,望有人能討論和幫忙。不
    發表于 05-07 16:30

    1831B直接訪問垂直操作說明

    1831B直接訪問垂直操作說明
    發表于 10-26 11:52

    python私有變量私有方法

    下劃線前導的方法,可以使用 實例._類名__方法名() 進行訪問私有變量私有方法,雖然有辦法訪問,但是仍然不建議使用上面給出的方法
    發表于 03-08 16:30

    UCOS擴展例程-UCOSIII直接訪問共享資源區

    UCOS擴展例程-UCOSIII直接訪問共享資源區
    發表于 12-14 17:24 ?20次下載

    匯編代碼訪問C全局變量

    12.2 匯編代碼訪問 C target=_blank style=cursor:pointer;color:#D05C38;text-decoration:underline;》C 全局變量
    發表于 10-19 09:25 ?0次下載

    Python私有變量的定義方法

    在類內部使用,不被外部調用,且當變量被標記為私有后,調用時需再變量的前端插入類名,在類名前添加一個下劃線,即“_ClassName__變量名”形式。Python
    發表于 02-13 16:49 ?1753次閱讀

    smarty如何調用PHP常量

    保留變量不需要從PHP腳本中分配,是可以在模板中直接訪問的數組類型變量,通常被用于訪問一些特殊的模板變量。例如,
    發表于 03-20 15:24 ?3次下載
    smarty如何調用PHP常量

    C++中類的繼承訪問級別學習總結(二)

    上一篇文章我們介紹了c++中類的繼承學習總結;今天我們繼續來分享c++中類的繼承中的訪問級別的學習總結。一、繼承中的訪問級別學習:1、子類是否可以直接訪問父類的私用成員嗎?面向對象理
    的頭像 發表于 12-24 16:10 ?894次閱讀

    python私有變量私有方法

    python私有變量私有方法 1. 下劃線妙用 在 Python 中,下劃線可是非常推薦使用的符號: 變量名推薦使用下劃線分隔的蛇形命名法 魔法方法、構造函數都需要使用雙下劃線 對于
    的頭像 發表于 03-08 16:30 ?2162次閱讀

    如何實現SIMATIC HMI對驅動參數的直接訪問

    SINAMICS V90PN驅動器可以通過模擬S7-CPU,將數據庫訪問HMI映射到驅動參數,該功能可實現在沒有SIMATIC S7控制器時,SIMATIC HMI對驅動參數的直接訪問
    的頭像 發表于 08-10 17:59 ?2262次閱讀
    如何<b class='flag-5'>實現</b>SIMATIC HMI對驅動參數的<b class='flag-5'>直接訪問</b>呢

    InfiniBand和遠程直接訪問是什么,如何進行配置

    本文簡單描述了InfiniBand 和遠程直接訪問(RDMA)是什么,以及在實踐中如何配置InfiniBand網絡硬件。另外,本文檔解釋了如何配置與 InfiniBand 相關的服務。
    的頭像 發表于 11-25 14:26 ?1945次閱讀

    實現HMI直接訪問驅動參數的方法

    SINAMICS V90PN驅動器可以通過模擬S7-CPU,將數據庫訪問HMI映射到驅動參數,該功能可實現在沒有SIMATIC S7控制器時,SIMATIC HMI對驅動參數的直接訪問
    的頭像 發表于 07-11 17:14 ?1077次閱讀
    <b class='flag-5'>實現</b>HMI<b class='flag-5'>直接訪問</b>驅動參數的方法

    STM32L4直接訪問內存模塊(DMA)介紹

    電子發燒友網站提供《STM32L4直接訪問內存模塊(DMA)介紹.pdf》資料免費下載
    發表于 08-01 10:15 ?1次下載
    STM32L4<b class='flag-5'>直接訪問</b>內存模塊(DMA)介紹