欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++聯(lián)合體union用法實(shí)例詳解

 更新時(shí)間:2015年05月26日 09:44:03   作者:巫祝  
這篇文章主要介紹了C++聯(lián)合體union用法,較為詳細(xì)的分析了C++中聯(lián)合體的概念、實(shí)用技巧及相關(guān)注意事項(xiàng),需要的朋友可以參考下

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

我們應(yīng)該按照C中的convention去使用union,這是我這篇文章要給出的觀(guān)點(diǎn)。雖然C++使得我們可以擴(kuò)展一些新的東西進(jìn)去,但是,我建議你不要那樣去做,看完這篇文章之后,我想你大概也是這么想的。

  C由于沒(méi)有類(lèi)的概念,所有類(lèi)型其實(shí)都可以看作是基本類(lèi)型的組合,因此在union中包含struct也就是一件很自然的事情了,到了C++之后,既然普遍認(rèn)為C++中的struct與class基本等價(jià),那么union中是否可以有類(lèi)成員呢?先來(lái)看看如下的代碼:

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

  而如果去掉那個(gè)什么也沒(méi)干的構(gòu)造函數(shù),則一切OK。

  為什么編譯器不允許我們的union成員有構(gòu)造函數(shù)呢?我無(wú)法找到關(guān)于這個(gè)問(wèn)題的比較權(quán)威的解釋?zhuān)瑢?duì)這個(gè)問(wèn)題,我的解釋是:

   如果C++標(biāo)準(zhǔn)允許我們的union有構(gòu)造函數(shù),那么,在進(jìn)行空間分配的時(shí)候要不要執(zhí)行這個(gè)構(gòu)造函數(shù)呢?如果答案是yes,那么如果TestUnion 的構(gòu)造函數(shù)中包含了一些內(nèi)存分配操作,或者其它對(duì)整個(gè)application狀態(tài)的修改,那么,如果我今后要用到obj的話(huà),事情可能還比較合理,但是如果我根本就不使用obj這個(gè)成員呢?由于obj的引入造成的對(duì)系統(tǒng)狀態(tài)的修改顯然是不合理的;反之,如果答案是no,那么一旦我們今后選中了obj來(lái)進(jìn)行 操作,則所有信息都沒(méi)有初始化(如果是普通的struct,沒(méi)什么問(wèn)題,但是,如果有虛函數(shù)呢?)。更進(jìn)一步,假設(shè)現(xiàn)在我們的union不是只有一個(gè) TestUnion obj,還有一個(gè)TestUnion2 obj2,二者均有構(gòu)造函數(shù),并且都在構(gòu)造函數(shù)中執(zhí)行了一些內(nèi)存分配的工作(甚至干了很多其它事情),那么,如果先構(gòu)造obj,后構(gòu)造obj2,則執(zhí)行的 結(jié)果幾乎可以肯定會(huì)造成內(nèi)存的泄漏。

  鑒于以上諸多麻煩(可能還有更多麻煩),在構(gòu)造union時(shí),編譯器只負(fù)責(zé)分配空間,而不負(fù)責(zé)去執(zhí)行附加的初始化工作,為了簡(jiǎn)化工作,只要我們提供了構(gòu)造函數(shù),就會(huì)收到上面的error。

同理,除了不能加構(gòu)造函數(shù),析構(gòu)函數(shù)/拷貝構(gòu)造函數(shù)/賦值運(yùn)算符也是不可以加。

  此外,如果我們的類(lèi)中包含了任何virtual函數(shù),編譯時(shí),我們將收到如下的錯(cuò)誤信息:
  error C2621: union '__unnamed' : member 'obj' has copy constructor

  所以,打消在union中包含有構(gòu)造函數(shù)/析構(gòu)函數(shù)/拷貝構(gòu)造函數(shù)/賦值運(yùn)算符/虛函數(shù)的類(lèi)成員變量的念頭,老老實(shí)實(shí)用你的C風(fēng)格struct吧!
  不過(guò),定義普通的成員函數(shù)是OK的,因?yàn)檫@不會(huì)使得class與C風(fēng)格的struct有任何本質(zhì)區(qū)別,你完全可以將這樣的class理解為一個(gè)C風(fēng)格的struct + n個(gè)全局函數(shù)。

  現(xiàn)在,再看看在類(lèi)中包含內(nèi)部union時(shí)會(huì)有什么不同。看看下面的程序,并請(qǐng)注意閱讀程序提示:

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也可以包含構(gòu)造函數(shù),但是,這雖然被語(yǔ)言所支持,但實(shí)在是一種不佳的編程習(xí)慣,因此,        我不打算對(duì)上面的程序進(jìn)行過(guò)多的說(shuō)明。我更推薦如下的編程風(fēng)格:

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風(fēng)格的。

所以,接受這個(gè)結(jié)論吧:

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

union是個(gè)好東西,union是個(gè)struct,里面所有成員共享一塊內(nèi)存,大小由size最大的member決定,存取成員的時(shí)候會(huì)以成員的類(lèi)型來(lái)解析這塊內(nèi)存;在gamedev中,union可以在這些方面有所作為:

1. 換名:

struct Rename
{
  public:
    union
    {
      struct 
      {
        float x,y,z,w;
      };
      struct
      {
        float vec[4];
      };
    };
};

 這樣我們既可以根據(jù)具體的含義來(lái)訪(fǎng)問(wèn)變量,也可以象數(shù)組一樣的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;
     };
   };
};

這樣對(duì)于集中處理的情況,比如==,就會(huì)大幅度提高效率,象在64位機(jī)上,只要一次,或者傳輸數(shù)據(jù)的情況,壓縮解壓縮都非常方便;

3. 危險(xiǎn):

匿名的union用法,不是standard,所以在compiler上要確認(rèn)==>編譯器移植性不好;
不同的機(jī)器操作系統(tǒng)上數(shù)據(jù)的size都是不一樣,表示不一樣,那么在用union的時(shí)候,尤其是在移植的時(shí)候,都是危險(xiǎn)的情況;
但是如果系統(tǒng),compiler都是一樣的話(huà),在合適的地方使用union還是可以的。

聯(lián)合(union)在C/C++里面見(jiàn)得并不多,但是在一些對(duì)內(nèi)存要求特別嚴(yán)格的地方,聯(lián)合又是頻繁出現(xiàn),那么究竟什么是聯(lián)合、怎么去用、有什么需要注意的地方呢?就這些問(wèn)題,我試著做一些簡(jiǎn)單的回答,里面肯定還有不當(dāng)?shù)牡胤?,歡迎指出!

1、什么是聯(lián)合?

“聯(lián)合”是一種特殊的類(lèi),也是一種構(gòu)造類(lèi)型的數(shù)據(jù)結(jié)構(gòu)。在一個(gè)“聯(lián)合”內(nèi)可以定義多種不同的數(shù)據(jù)類(lèi)型, 一個(gè)被說(shuō)明為該“聯(lián)合”類(lèi)型的變量中,允許裝入該“聯(lián)合”所定義的任何一種數(shù)據(jù),這些數(shù)據(jù)共享同一段內(nèi)存,已達(dá)到節(jié)省空間的目的(還有一個(gè)節(jié)省空間的類(lèi)型:位域)。 這是一個(gè)非常特殊的地方,也是聯(lián)合的特征。另外,同struct一樣,聯(lián)合默認(rèn)訪(fǎng)問(wèn)權(quán)限也是公有的,并且,也具有成員函數(shù)。

2、聯(lián)合與結(jié)構(gòu)的區(qū)別?

“聯(lián)合”與“結(jié)構(gòu)”有一些相似之處。但兩者有本質(zhì)上的不同。在結(jié)構(gòu)中各成員有各自的內(nèi)存空間, 一個(gè)結(jié)構(gòu)變量的總長(zhǎng)度是各成員長(zhǎng)度之和(空結(jié)構(gòu)除外,同時(shí)不考慮邊界調(diào)整)。而在“聯(lián)合”中,各成員共享一段內(nèi)存空間, 一個(gè)聯(lián)合變量的長(zhǎng)度等于各成員中最長(zhǎng)的長(zhǎng)度。應(yīng)該說(shuō)明的是, 這里所謂的共享不是指把多個(gè)成員同時(shí)裝入一個(gè)聯(lián)合變量?jī)?nèi), 而是指該聯(lián)合變量可被賦予任一成員值,但每次只能賦一種值, 賦入新值則沖去舊值。

下面舉一個(gè)例了來(lái)加對(duì)深聯(lián)合的理解。

例4:

#include <stdio.h>
void main()
{
  union number
  { /*定義一個(gè)聯(lián)合*/
   int i;
   struct
   { /*在聯(lián)合中定義一個(gè)結(jié)構(gòu)*/
    char first;
    char second;
   }half;
  }num;
  num.i=0x4241; /*聯(lián)合成員賦值*/
  printf("%c%c\n", num.half.first, num.half.second);
  num.half.first='a'; /*聯(lián)合中結(jié)構(gòu)成員賦值*/
  num.half.second='b';
  printf("%x\n", num.i);
  getchar();
}

輸出結(jié)果為:

AB
6261

從上例結(jié)果可以看出: 當(dāng)給i賦值后, 其低八位也就是first和second的值; 當(dāng)給first和second賦字符后, 這兩個(gè)字符的ASCII碼也將作為i 的低八位和高八位。

3、如何定義?

例如:

union test
{
  test() { }
  int office;
  char teacher[5];
};

定義了一個(gè)名為test的聯(lián)合類(lèi)型,它含有兩個(gè)成員,一個(gè)為整型,成員名office;另一個(gè)為字符數(shù)組,數(shù)組名為teacher。聯(lián)合定義之后,即可進(jìn)行聯(lián)合變量說(shuō)明,被說(shuō)明為test類(lèi)型的變量,可以存放整型量office或存放字符數(shù)組teacher。

4、如何說(shuō)明?

聯(lián)合變量的說(shuō)明有三種形式:先定義再說(shuō)明、定義同時(shí)說(shuō)明和直接說(shuō)明。

以test類(lèi)型為例,說(shuō)明如下:
1)

union test
{
  int office;
  char teacher[5];
}; 
union test a,b; /*說(shuō)明a,b為test類(lèi)型*/

2)

union test
{
  int office;
  char teacher[5];
} a,b;

3)

union 
{
  int office;
  char teacher[5];
} a,b;

經(jīng)說(shuō)明后的a,b變量均為test類(lèi)型。a,b變量的長(zhǎng)度應(yīng)等于test的成員中最長(zhǎng)的長(zhǎng)度,即等于teacher數(shù)組的長(zhǎng)度,共5個(gè)字節(jié)。a,b變量如賦予整型值時(shí),只使用了4個(gè)字節(jié),而賦予字符數(shù)組時(shí),可用5個(gè)字節(jié)。

5、如何使用?

對(duì)聯(lián)合變量的賦值,使用都只能是對(duì)變量的成員進(jìn)行。聯(lián)合變量的成員表示為:
聯(lián)合變量名.成員名
例如,a被說(shuō)明為test類(lèi)型的變量之后,可使用a.class、a.office
不允許只用聯(lián)合變量名作賦值或其它操作,也不允許對(duì)聯(lián)合變量作初始化賦值,賦值只能在程序中進(jìn)行。
還要再?gòu)?qiáng)調(diào)說(shuō)明的是,一個(gè)聯(lián)合變量,每次只能賦予一個(gè)成員值。換句話(huà)說(shuō),一個(gè)聯(lián)合變量的值就是聯(lián)合變員的某一個(gè)成員值。

6、匿名聯(lián)合

匿名聯(lián)合僅僅通知編譯器它的成員變量共同享一個(gè)地址,而變量本身是直接引用的,不使用通常的點(diǎn)號(hào)運(yùn)算符語(yǔ)法.
例如:

#include <iostream>
void main()
{
  union{ 
  int test;
  char c; 
  }; 
  test=5;
  c='a';
  std::cout<<i<<" "<<c;
}

正如所見(jiàn)到的,聯(lián)合成分象聲明的普通局部變量那樣被引用,事實(shí)上對(duì)于程序而言,這也正是使用這些變量的方式.另外,盡管被定義在一個(gè)聯(lián)合聲明中,他們與同一個(gè)程序快那的任何其他局部變量具有相同的作用域級(jí)別.這意味這匿名聯(lián)合內(nèi)的成員的名稱(chēng)不能與同一個(gè)作用域內(nèi)的其他一直標(biāo)志符沖突.
對(duì)匿名聯(lián)合還存在如下限制:
因?yàn)槟涿?lián)合不使用點(diǎn)運(yùn)算符,所以包含在匿名聯(lián)合內(nèi)的元素必須是數(shù)據(jù),不允許有成員函數(shù),也不能包含私有或受保護(hù)的成員。還有,全局匿名聯(lián)合必須是靜態(tài)(static)的,否則就必須放在匿名名字空間中。

7、幾點(diǎn)需要討論的地方:

1)聯(lián)合里面那些東西不能存放?

我們知道,聯(lián)合里面的東西共享內(nèi)存,所以靜態(tài)、引用都不能用,因?yàn)樗麄儾豢赡芄蚕韮?nèi)存。

2)類(lèi)可以放入聯(lián)合嗎?

我們先看一個(gè)例子:

class Test
{
  public:
  Test():data(0) { }
  private:
  int data;
};
typedef union _test
{
  Test test; 
}UI; 

編譯通不過(guò),為什么呢?
因?yàn)槁?lián)合里不允許存放帶有構(gòu)造函數(shù)、析夠函數(shù)、復(fù)制拷貝操作符等的類(lèi),因?yàn)樗麄児蚕韮?nèi)存,編譯器無(wú)法保證這些對(duì)象不被破壞,也無(wú)法保證離開(kāi)時(shí)調(diào)用析夠函數(shù)。

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) {
}

看出什么問(wèn)題了嗎?呵呵,編譯通不過(guò)。為什么呢?難道datatype.ch(p)和datatype.l(i)有問(wèn)題嗎?
哈哈,問(wèn)題在哪呢?讓我們來(lái)看看構(gòu)造test對(duì)象時(shí)發(fā)生了什么,當(dāng)創(chuàng)建test對(duì)象時(shí),自然要調(diào)用其相應(yīng)的構(gòu)造函數(shù),在構(gòu)造函數(shù)中當(dāng)然要調(diào)用其成員的構(gòu)造函數(shù),所以其要去調(diào)用datatype成員的構(gòu)造函數(shù),但是他沒(méi)有構(gòu)造函數(shù)可調(diào)用,所以出
錯(cuò)。
注意了,這里可并不是匿名聯(lián)合!因?yàn)樗竺婢o跟了個(gè)data!

4)如何有效的防止訪(fǎng)問(wèn)出錯(cuò)?

使用聯(lián)合可以節(jié)省內(nèi)存空間,但是也有一定的風(fēng)險(xiǎn):通過(guò)一個(gè)不適當(dāng)?shù)臄?shù)據(jù)成員獲取當(dāng)前對(duì)象的值!例如上面的ch、i交錯(cuò)訪(fǎng)問(wèn)。

為了防止這樣的錯(cuò)誤,我們必須定義一個(gè)額外的對(duì)象,來(lái)跟蹤當(dāng)前被存儲(chǔ)在聯(lián)合中的值得類(lèi)型,我們稱(chēng)這個(gè)額外的對(duì)象為:union的判別式。

一個(gè)比較好的經(jīng)驗(yàn)是,在處理作為類(lèi)成員的union對(duì)象時(shí),為所有union數(shù)據(jù)類(lèi)型提供一組訪(fǎng)問(wèn)函數(shù)。

希望本文所述對(duì)大家的C++程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • C++?結(jié)合?opencv讀取圖片與視頻的方法

    C++?結(jié)合?opencv讀取圖片與視頻的方法

    這篇文章主要介紹了C++?結(jié)合?opencv讀取圖片與視頻,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 淺析C++如何跨模塊釋放內(nèi)存

    淺析C++如何跨模塊釋放內(nèi)存

    這篇文章主要為大家詳細(xì)介紹了C++中跨模塊釋放內(nèi)存的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以了解下
    2024-02-02
  • Qt地圖自適應(yīng)拉伸的實(shí)現(xiàn)示例

    Qt地圖自適應(yīng)拉伸的實(shí)現(xiàn)示例

    最近需要寫(xiě)一個(gè)程序,要是讓qt到程序自適應(yīng),本文主要介紹了Qt地圖自適應(yīng)拉伸的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 詳解C++編程中的條件判斷語(yǔ)句if-else與switch的用法

    詳解C++編程中的條件判斷語(yǔ)句if-else與switch的用法

    這篇文章主要介紹了C++編程中的條件判斷語(yǔ)句if-else與switch的用法,是C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-01-01
  • c++指針參數(shù)傳遞和引用參數(shù)傳遞的區(qū)別解析

    c++指針參數(shù)傳遞和引用參數(shù)傳遞的區(qū)別解析

    這篇文章主要介紹了c++指針參數(shù)傳遞和引用參數(shù)傳遞的區(qū)別解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • C++線(xiàn)程安全的隊(duì)列你了解嘛

    C++線(xiàn)程安全的隊(duì)列你了解嘛

    這篇文章主要為大家詳細(xì)介紹了C++線(xiàn)程安全的隊(duì)列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • C語(yǔ)言字符串?dāng)?shù)組詳解

    C語(yǔ)言字符串?dāng)?shù)組詳解

    這篇文章主要介紹了C語(yǔ)言字符串?dāng)?shù)組詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • C++ 函數(shù)指針詳細(xì)總結(jié)

    C++ 函數(shù)指針詳細(xì)總結(jié)

    這篇文章主要介紹了C++ 函數(shù)指針內(nèi)容,下面文章圍繞C++ 函數(shù)指針的相關(guān)資料展開(kāi)詳細(xì)內(nèi)容,包括函數(shù)指針的進(jìn)階內(nèi)容,需要的朋友可以參考一下,希望對(duì)大家有所幫助
    2021-11-11
  • C++實(shí)現(xiàn)尋找最低公共父節(jié)點(diǎn)的方法

    C++實(shí)現(xiàn)尋找最低公共父節(jié)點(diǎn)的方法

    這篇文章主要介紹了C++實(shí)現(xiàn)尋找最低公共父節(jié)點(diǎn)的方法,是數(shù)據(jù)結(jié)構(gòu)中二叉樹(shù)的一個(gè)經(jīng)典算法,有一定的借鑒價(jià)值,需要的朋友可以參考下
    2014-09-09
  • VSstudio中scanf返回值被忽略的原因及解決方法(推薦)

    VSstudio中scanf返回值被忽略的原因及解決方法(推薦)

    這篇文章主要介紹了VSstudio中scanf返回值被忽略的原因及其解決方法,scanf返回值被忽略,接下來(lái)我就告訴大家該如何解決這個(gè)問(wèn)題,需要的朋友可以參考下
    2022-09-09

最新評(píng)論