本文實例講述了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; }; }; };