萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> 編程語言綜合 >> C++聯合體union用法實例詳解

C++聯合體union用法實例詳解

   本文實例講述了C++聯合體union用法。分享給大家供大家參考。具體如下:

  我們應該按照C中的convention去使用union,這是我這篇文章要給出的觀點。雖然C++使得我們可以擴展一些新的東西進去,但是,我建議你不要那樣去做,看完這篇文章之後,我想你大概也是這麼想的。

  C由於沒有類的概念,所有類型其實都可以看作是基本類型的組合,因此在union中包含struct也就是一件很自然的事情了,到了C++之後,既然普遍認為C++中的struct與class基本等價,那麼union中是否可以有類成員呢?先來看看如下的代碼:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct TestUnion {    TestUnion() {} };   typedef union {    TestUnion obj; } UT;   int main (void) {    return 0; }

  編譯該程序,我們將被告知:

  error C2620: union '__unnamed' : member 'obj' has user-defined constructor or non-trivial default constructor

  而如果去掉那個什麼也沒干的構造函數,則一切OK。

  為什麼編譯器不允許我們的union成員有構造函數呢?我無法找到關於這個問題的比較權威的解釋,對這個問題,我的解釋是:

  如果C++標准允許我們的union有構造函數,那麼,在進行空間分配的時候要不要執行這個構造函數呢?如果答案是yes,那麼如果TestUnion 的構造函數中包含了一些內存分配操作,或者其它對整個application狀態的修改,那麼,如果我今後要用到obj的話,事情可能還比較合理,但是如果我根本就不使用obj這個成員呢?由於obj的引入造成的對系統狀態的修改顯然是不合理的;反之,如果答案是no,那麼一旦我們今後選中了obj來進行 操作,則所有信息都沒有初始化(如果是普通的struct,沒什麼問題,但是,如果有虛函數呢?)。更進一步,假設現在我們的union不是只有一個 TestUnion obj,還有一個TestUnion2 obj2,二者均有構造函數,並且都在構造函數中執行了一些內存分配的工作(甚至干了很多其它事情),那麼,如果先構造obj,後構造obj2,則執行的 結果幾乎可以肯定會造成內存的洩漏。

  鑒於以上諸多麻煩(可能還有更多麻煩),在構造union時,編譯器只負責分配空間,而不負責去執行附加的初始化工作,為了簡化工作,只要我們提供了構造函數,就會收到上面的error。

  同理,除了不能加構造函數,析構函數/拷貝構造函數/賦值運算符也是不可以加。

  此外,如果我們的類中包含了任何virtual函數,編譯時,我們將收到如下的錯誤信息:

  error C2621: union '__unnamed' : member 'obj' has copy constructor

  所以,打消在union中包含有構造函數/析構函數/拷貝構造函數/賦值運算符/虛函數的類成員變量的念頭,老老實實用你的C風格struct吧!

  不過,定義普通的成員函數是OK的,因為這不會使得class與C風格的struct有任何本質區別,你完全可以將這樣的class理解為一個C風格的struct + n個全局函數。

  現在,再看看在類中包含內部union時會有什麼不同。看看下面的程序,並請注意閱讀程序提示:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class TestUnion {    union DataUnion    {    DataUnion(const char*);    DataUnion(long);    const char* ch_;    long l_;    } data_;     public:    TestUnion(const char* ch);    TestUnion(long l); };   TestUnion::TestUnion(const char* ch) : data_(ch) // if you want to use initialzing list to initiate a nested-union member, the union must not be anonymous and must have a constructor。 {}   TestUnion::TestUnion(long l) : data_(l) {}   TestUnion::DataUnion::DataUnion(const char* ch) : ch_(ch) {}   TestUnion::DataUnion::DataUnion(long l) : l_(l) {}   int main (void) {    return 0; }

  正如上面程序所示,C++中的union也可以包含構造函數,但是,這雖然被語言所支持,但實在是一種不佳的編程習慣,因此, 我不打算對上面的程序進行過多的說明。我更推薦如下的編程風格:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class TestUnion {    union DataUnion    {    const char* ch_;    long l_;    } data_;      public:    TestUnion(const char* ch);    TestUnion(long l); };   TestUnion::TestUnion(const char* ch) {    data_.ch_ = ch; }   TestUnion::TestUnion(long l) {    data_.l_ = l; }   int main (void) {    return 0; }

  它完全是C風格的。

  所以,接受這個結論吧:

  請按照C中的convention去使用union,盡量不要嘗試使用任何C++附加特性。

  union是個好東西,union是個struct,裡面所有成員共享一塊內存,大小由size最大的member決定,存取成員的時候會以成員的類型來解析這塊內存;在gamedev中,union可以在這些方面有所作為:

  1. 換名:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct Rename { public: union { struct { float x,y,z,w; }; struct { float vec[4]; }; }; };

  這樣我們既可以根據具體的含義來訪問變量,也可以象數組一樣的loop;

  2 .壓縮:

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct Compression { public: bool operator==(const Compression& arg) const { return value == arg.value; } union { struct { char a,b,c,d,e,f,g; }; struct { long long value; }; }; };
copyright © 萬盛學電腦網 all rights reserved