結構體(struct)與共用體(union)是C語言中就已經存在的資料型別,C++對他們進行了擴充,最大的變化是允許在結構和公用體中定義成員函式,下面將通過實體講解二者的特性和用法,

1.struct
以下是一個使用了結構體的C++程式,
#include <iostream>
usingnamespacestd;
structRoom
{
intfloor;
intNo;
};
structStudent
{
intage;
intscore;
Student(inta,ints){
age=a;
score=s;
}
};
intmain(intargc,char* argv[])
{
Room r[3]={{1,101},{2,201},{3,301}};
Student s(18,89);
cout<<"the room are:";
cout<<r[0].floor<<"-"<<r[0].No<<" ";
cout<<r[1].floor<<"-"<<r[1].No<<" ";
cout<<r[2].floor<<"-"<<r[2].No<<endl;
cout<<"the student's age:"<<s.age<<" score:"<<s.score<<endl;
getchar();
}
程式運行結果:
the room are:1-101 2-201 3-301
the student's age:18 score:89
閱讀以上程式,在C++中使用結構體需要注意以下幾點:
(1)C++中,結構體是一種真正的資料型別,在利用結構定義變數時,不需要像在C中帶上struct關鍵字,或先使用typedef struct structname structalias的方式進行申明,
(2)C++對C中的struct進行了擴充,允許在struct中定義成員函式,struct中的成員變數和成員函式也有訪問權限,在class中,默認的訪問權限是private,而在struct中默認訪問權限是public,這是結構體和類的唯一區別,struct成員的默認訪問權限設為public是C++保持與C語言兼容而采取的一項策略,
(3)如果struct中沒有顯示定義任何建構式,那么結構變數可以像在C語言中那樣用花括號順序指明資料成員的值來進行初始化,但是一旦顯示定義了任何一個建構式,就不能用這種方式初始化了,如果在class中只有若干public型的資料成員,而沒有顯示定義任何建構式,也可以使用花括號進行初始化,
(4)用sizeof運算子計算結構的大小時,要考慮結構體內部變數的對齊問題,

2.union
共用體(union),又名聯合體,是一種特殊的類,從C語言章繼承而來,其基本語意沒有發生什么變化,只是具有了類的一些特性(允許定義成員函式),在實際的編程實踐中,使用頻率沒有struct高,與struct相比,最顯著的區別是union的資料成員共享同一段記憶體,以達到節省空間的目的,
2.1 union的基本性質
通過如下程式考察union變數的占用空間,成員賦值時的相互影響,
#include <iostream>
usingnamespacestd;
uniontestunion
{
charc;
inti;
};
intmain(intargc,char* argv[])
{
cout<<sizeof(testunion)<<endl;
testunion* pt=newtestunion;
char* p=reinterpret_cast<char*>(pt);
for(inti=0;i<sizeof(*pt);i++)
cout<<int(p[i])<<" ";
cout<<endl;
cout<<pt->i<<endl;
pt->c='A';
cout<<pt->c<<endl;
for(inti=0;i<sizeof(*pt);i++)
cout<<int(p[i])<<" ";
cout<<endl;
cout<<pt->i<<endl;
deletept;
}
程式運行結果:
4
-51 -51 -51 -51
-842150451
A
65 -51 -51 -51
-842150591
可以看出,union testunion變數的體積是4,它是由兩個資料成員中體積較大的一個(int)型別來決定的,對其中一個資料成員的修改,一定會同時改變所有其他資料成員的值,不過對體積較小的資料成員的修改,只會影響到該成員應該占用的那些位元組,對超出部分(高位位元組)沒有什么影響,
2.2 union的高級特性
觀察如下程式,
#include <iostream>
usingnamespacestd;
structStudent
{
intage;
intscore;
Student(inta,ints)
{
age=a;
score=s;
}
};
uniontestunion
{
charc;
inti;
};
classsomeClass
{
intnum;
public:
voidshow(){cout<<num<<endl;}
};
unionA
{
charc;
inti;
doubled;
someClass s;
};
unionB
{
charc;
inti;
doubled;
B(){d=8.9;}
};
union
{
charc;
inti;
doubled;
voidshow(){cout<<c<<endl;}
}u={'U'};
intmain(intargc,char* argv[])
{
A a={'A'};
B b;
cout<<a.c<<endl;
cout<<b.d<<endl;
a.s.show();
u.show();
//匿名共用體
union
{
intp;
intq;
};
p=3;
cout<<q<<endl;
}
程式運行結果:
A
8.9
65
U
3

閱讀以上程式,需要注意以下幾點:
(1)union可以指定成員的訪問權限,默認情況下,與struct具有一樣的權限(public),
(2)union也可以定義成員函式,包括建構式和解構式,與struct不同的是,它不能作為基類被繼承,
(3)union不能擁有靜態資料成員或參考成員,因為靜態資料成員實際上并不是共用體的資料成員,它無法和共用體的其它資料成員共享空間,對于參考變數,參考本質上是一個指標常量,它的值一旦初始化就不允許修改,如果共用體有參考成員,那么共用體物件一創建初始化后就無法修改,只能作為一個普通的參考使用,這就失去了共用體存在的意義,
(4)union允許其他類的物件成為自己的資料成員,但是要求該類物件所屬類不能定義constructor,copy constructor,destructor,assignment operator,virtual function中的任意一個,因為:
(4.1)union資料成員共享記憶體,union建構式在執行的時候,不能呼叫資料成員為類物件的建構式,否則就改變了其他資料成員的值,
(4.2)同樣,union的物件成員的解構式也不能被呼叫,因為其他資料成員的值對于物件成員而言可能毫無意義,
(4.3)union的物件成員的賦值應該維持其原始語意,不建議進行賦值運算子的多載,因為賦值運算子多載一般用于“深拷貝”等場合,而在物件空間與其它變數共享的情況下,“深拷貝”引入的記憶體資源,指向記憶體資源的指標往往會被其它共用體資料成員修改,導致記憶體資源無法尋址,造成記憶體泄漏,此外,因為union的物件成員沒有自定義的解構式,也會導致記憶體泄漏,
(4.4)擁有虛函式的類物件,虛函式表指標可能會在共用體物件初始化時被覆寫,導致無法尋址虛函式表,所以也不能擁有虛函式,
(5)如果union型別旨在定義該類的同時使用一次,以后不再使用了,那么也可以不給出union的名稱,如上例中變數u就是這種情況,這種情況下,無法為該union定義建構式,
(6)匿名共用體(Anonymous Union),也就是給出一個不帶名稱的共用體的申明后,并不定義任何該union的變數,而是直接以分號結尾,嚴格來說,匿名共用體并不是一種資料結構,因為它不能用來定義共用體物件,它只是指明若干個變數共享一片記憶體單元,在上例中,對變數p的修改實際上修改了變數q,可以看出,盡管匿名共用體中的變數被定義在同一個共用體中,他們與同一個程式塊的任何其他區域變數具有相同的作用域級別,這意味著匿名共用體內的成員的名稱不能與同一個作用域內的其它識別符號相沖突,另外,對匿名共用體還存在如下限制:
(6.1)匿名共用體不允許有成員函式;
(6.2)匿名共用體也不能包含私有或者保護成員;
(6.3)全域匿名共用體中的成員必須是全域或靜態變數,
以上就是深入了解C++ 結構體(struct)與共用體(union)的詳細內容,有什么問題歡迎大家評論區留言,

最后,如果你也想成為程式員,想要快速掌握編程,趕緊加入學習企鵝圈子!
里面有資深專業軟體開發工程師,在線解答你的所有疑惑~編程語言入門“so easy”
編程學習書籍:

編程學習視頻:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/236386.html
標籤:其他
