C++結合體union用法實例詳解。本站提示廣大學習愛好者:(C++結合體union用法實例詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++結合體union用法實例詳解正文
本文實例講述了C++結合體union用法。分享給年夜家供年夜家參考。詳細以下:
我們應當依照C中的convention去應用union,這是我這篇文章要給出的不雅點。固然C++使得我們可以擴大一些新的器械出來,然則,我建議你不要那樣去做,看完這篇文章以後,我想你年夜概也是這麼想的。
C因為沒有類的概念,一切類型其實都可以看做是根本類型的組合,是以在union中包括struct也就是一件很天然的工作了,到了C++以後,既然廣泛以為C++中的struct與class根本等價,那末union中能否可以有類成員呢?先來看看以下的代碼:
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時會有甚麼分歧。看看上面的法式,並請留意浏覽法式提醒:
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也能夠包括結構函數,然則,這固然被說話所支撐,但其實是一種欠安的編程習氣,是以, 我不盤算對下面的法式停止過量的解釋。我更推舉以下的編程作風:
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. 換名:
struct Rename { public: union { struct { float x,y,z,w; }; struct { float vec[4]; }; }; };
如許我們既可以依據詳細的寄義來拜訪變量,也能夠象數組一樣的loop;
2 .緊縮:
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; }; }; };
如許關於集中處置的情形,好比==,就會年夜幅度進步效力,象在64位機上,只需一次,或許傳輸數據的情形,緊縮解緊縮都異常便利;
3. 風險:
匿名的union用法,不是standard,所以在compiler上要確認==>編譯器移植性欠好;
分歧的機械操作體系上數據的size都是紛歧樣,表現紛歧樣,那末在用union的時刻,特別是在移植的時刻,都是風險的情形;
然則假如體系,compiler都是一樣的話,在適合的處所應用union照樣可以的。
結合(union)在C/C++外面見得其實不多,然則在一些對內存請求特殊嚴厲的處所,結合又是頻仍湧現,那末畢竟甚麼是結合、怎樣去用、有甚麼須要留意的處所呢?就這些成績,我試著做一些簡略的答復,外面確定還有欠妥的處所,迎接指出!
1、甚麼是結合?
“結合”是一種特別的類,也是一種結構類型的數據構造。在一個“結合”內可以界說多種分歧的數據類型, 一個被解釋為該“結合”類型的變量中,許可裝入該“結合”所界說的任何一種數據,這些數據同享統一段內存,已到達節儉空間的目標(還有一個節儉空間的類型:位域)。 這是一個異常特別的處所,也是結合的特點。別的,同struct一樣,結合默許拜訪權限也是私有的,而且,也具有成員函數。
2、結合與構造的差別?
“結合”與“構造”有一些類似的地方。但二者有實質上的分歧。在構造中各成員有各自的內存空間, 一個構造變量的總長度是各成員長度之和(空構造除外,同時不斟酌界限調劑)。而在“結合”中,各成員同享一段內存空間, 一個結合變量的長度等於各成員中最長的長度。應當解釋的是, 這裡所謂的同享不是指把多個成員同古裝入一個結合變量內, 而是指該結合變量可被付與任一成員值,但每次只能賦一種值, 賦入新值則沖去舊值。
上面舉一個例了來加對深結合的懂得。
例4:
#include <stdio.h> void main() { union number { /*界說一個結合*/ int i; struct { /*在結合中界說一個構造*/ char first; char second; }half; }num; num.i=0x4241; /*結合成員賦值*/ printf("%c%c\n", num.half.first, num.half.second); num.half.first='a'; /*結合中構造成員賦值*/ num.half.second='b'; printf("%x\n", num.i); getchar(); }
輸入成果為:
AB
6261
從上例成果可以看出: 當給i賦值後, 其低八位也就是first和second的值; 當給first和second賦字符後, 這兩個字符的ASCII碼也將作為i 的低八位和高八位。
3、若何界說?
例如:
union test { test() { } int office; char teacher[5]; };
界說了一個名為test的結合類型,它含有兩個成員,一個為整型,成員名office;另外一個為字符數組,數組名為teacher。結合界說以後,便可停止結合變量解釋,被解釋為test類型的變量,可以寄存整型量office或寄存字符數組teacher。
4、若何解釋?
結合變量的解釋有三種情勢:先界說再解釋、界說同時解釋和直接解釋。
以test類型為例,解釋以下:
1)
union test { int office; char teacher[5]; }; union test a,b; /*解釋a,b為test類型*/
2)
union test { int office; char teacher[5]; } a,b;
3)
union { int office; char teacher[5]; } a,b;
經解釋後的a,b變量均為test類型。a,b變量的長度應等於test的成員中最長的長度,即等於teacher數組的長度,共5個字節。a,b變量如付與整型值時,只應用了4個字節,而付與字符數組時,可用5個字節。
5、若何應用?
春聯合變量的賦值,應用都只能是對變量的成員停止。結合變量的成員表現為:
結合變量名.成員名
例如,a被解釋為test類型的變量以後,可以使用a.class、a.office
不許可只用結合變量名作賦值或其它操作,也不許可春聯合變量作初始化賦值,賦值只能在法式中停止。
還要再強調解釋的是,一個結合變量,每次只能付與一個成員值。換句話說,一個結合變量的值就是結合變員的某一個成員值。
6、匿名結合
匿名結合僅僅告訴編譯器它的成員變量配合享一個地址,而變量自己是直接援用的,不應用平日的點號運算符語法.
例如:
#include <iostream> void main() { union{ int test; char c; }; test=5; c='a'; std::cout<<i<<" "<<c; }
正如所見到的,結合成份象聲明的通俗部分變量那樣被援用,現實上關於法式而言,這也恰是應用這些變量的方法.別的,雖然被界說在一個結合聲明中,他們與統一個法式快那的任何其他部分變量具有雷同的感化域級別.這意味這匿名結合內的成員的稱號不克不及與統一個感化域內的其他一向標記符抵觸.
對匿名結合還存在以下限制:
由於匿名結合不應用點運算符,所以包括在匿名結合內的元素必需是數據,不許可有成員函數,也不克不及包括公有或受掩護的成員。還有,全局匿名結合必需是靜態(static)的,不然就必需放在匿名名字空間中。
7、幾點須要評論辯論的處所:
1)結合外面那些器械不克不及寄存?
我們曉得,結合外面的器械同享內存,所以靜態、援用都不克不及用,由於他們弗成能同享內存。
2)類可以放入結合嗎?
我們先看一個例子:
class Test { public: Test():data(0) { } private: int data; }; typedef union _test { Test test; }UI;
編譯通不外,為何呢?
由於結合裡不許可寄存帶有結構函數、析夠函數、復制拷貝操作符等的類,由於他們同享內存,編譯器沒法包管這些對象不被損壞,也沒法包管分開時挪用析夠函數。
3)又是匿名惹的禍??
我們先看下一段代碼:
class test { public: test(const char* p); test(int in); const operator char*() const {return data.ch;} operator long() const {return data.l;} private: enum type {Int, String }; union { const char* ch; int i; }datatype; type stype; test(test&); test& operator=(const test&); }; test::test(const char *p):stype (String),datatype.ch(p) { } test::test(int in):stype(Int),datatype.l(i) { }
看出甚麼成績了嗎?呵呵,編譯通不外。為何呢?豈非datatype.ch(p)和datatype.l(i)有成績嗎?
哈哈,成績在哪呢?讓我們來看看結構test對象時產生了甚麼,當創立test對象時,天然要挪用其響應的結構函數,在結構函數中固然要挪用其成員的結構函數,所以其要去挪用datatype成員的結構函數,然則他沒有結構函數可挪用,所以出
錯。
留意了,這裡可其實不是匿名結合!由於它前面緊跟了個data!
4)若何有用的避免拜訪失足?
應用結合可以節儉內存空間,然則也有必定的風險:經由過程一個不恰當的數據成員獲得以後對象的值!例如下面的ch、i交織拜訪。
為了避免如許的毛病,我們必需界說一個額定的對象,來跟蹤以後被存儲在結合中的值得類型,我們稱這個額定的對象為:union的辨別式。
一個比擬好的經歷是,在處置作為類成員的union對象時,為一切union數據類型供給一組拜訪函數。
願望本文所述對年夜家的C++法式設計有所贊助。