溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

c++中class遇上union會怎么樣

發布時間:2022-01-05 17:06:23 來源:億速云 閱讀:147 作者:iii 欄目:大數據

這篇文章主要介紹“c++中class遇上union會怎么樣”,在日常操作中,相信很多人在c++中class遇上union會怎么樣問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”c++中class遇上union會怎么樣”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

由于面向對象的存在, 在代碼中常常有這樣一種用于存儲屬性的類,類A,類B, 類C,類B繼承自類A,類C繼承自類B。 而類A, 類B, 類C等這些類的實例都是從socket層傳過來的。

作者在設計時為了代碼的復用性, 采用了如下設計:

union object {
       class A         a;
       class B         b;
       class C         c;
};

//read_objectX_from_socket函數為偽碼, 其實現為逐個讀出某個類的成員, 至于這個函數為什么會是這樣實現, 這是socket層上的另一個設計問題了, 暫且不談

void readA(union object &o)
{
       read_objectA_from_socket(o.a);
}

void readB(union object &o)
{
       readA(o);
       read_objectB_from_socket(o.b);
}

void readC(union object &o)

{
       readB(o);
       read_objectC_from_socket(o.c);
}

從上面看出作者對于C++中的成員變量的內存布局相當有信心, 才會想到使用union的方式來復用代碼。

假設這三個類的成員定義如下:class A {int a;}, class B : public A {int b;}, class C : public B {int c;}.

那么此union中的內存布局其實就是A::a, B::b, C::c。


object::a所占的空間就是A::a在union中所占的內存
object::b所占的空間就是A::a和B::b在union中所占的內存
object::c所占的空間就是A::a和B::b和B::c在union中所占的內存

設計者巧妙的利用了union的重疊特性和class的繼承特性來完成了代碼復用。

大約在上學的時候我也喜歡去hack內存布局(當然沒有這種用法這么巧妙), 后來我便漸漸不大喜歡這種做法了.

因為這種代碼雖然寫起來有種炫技的自豪感, 但事實上一旦出了bug是極難發現的, 人類在匯編語言基礎之上又發明了高級語言, 我想也正是因為他們覺得人們需要更多的規則來幫人們減少出錯的可能性, 所以我后來便一直主張寫出更多可以讓編譯器檢查出錯誤的代碼。


同事踩的坑也正驗證了hack內存布局易錯不易查的事實。 由于某種偷懶原因, 他實現了class D : public B {int d;}, class F : public C, public D { int f;}。而readF的實現代碼如下:


void readF(union object &o)
{
       readC(o);
       readD(o);

       read_objectF_from_socket(o.c);
}

在實現readD時代碼看起來依然正常運行, 但是在實現readF時, 明明看到有數據讀入,但是類F中繼承自C和D的成員總是莫名其妙亂掉(當然這不是我發現的, 這個bug只是我事后知道的罷了)。

此時重新看一下union, 那么C::c和D::d占用的是同一片內存, 那么其實在readF中調用readC和readD時, 覆蓋的總是同一塊內存。

再看class F的內存布局應該是A::a, b::b, C::c, D::d, f, 也就是說整個readF執行下來, 其實F::D::d這個變量從來就沒被操作過, 也就不可能賦值, 由于棧中的隨機數, 所以F::D::d這個變量也就變得隨機了, 由于object::C::c所占的內存總是會被readC和readD同時操作。因此看上去數據也不那么的有跡可尋。


當第一眼看到這種設計時, 雖然覺得不妥, 但是我并沒有找到一種可以不通過hack內存來達到最大代碼復用的方式。

在下班回來的路上, 我總覺得應該可以不通過hack內存來達到同樣的目的, 終于在快到住的地方時被我想到的了。 

其實很簡單, 之所以想不到一方面是我不常用C++, 另一方面大概是之前看了這段代碼, 一時間先入為主, 思維沒有緩過勁來。

其實只需要按照C++最常規的dynamic_cast就可以完成代碼的最大復用。

代碼接口大概實現如下:


void readA(class A *a)
{
       //read a members
}

....

void readD(class F *a)
{
       readB(a);
       //read D members
}

由于是dynamic_cast, 因此編譯器可以幫我們自動去計算每個成員的偏移量, 避免了手動hack可能出現的各種錯誤。

btw,使用dynamic_cast的方式僅僅能依靠編譯器發現這種hack內存時容易出現的bug。 在碰到類似class F這種使用多重繼承機制的類時,編譯器僅僅會報語法錯誤,并不能對其父類的readX函數進行復用。

到此,關于“c++中class遇上union會怎么樣”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女