C++/C學習筆記(七)

weixin_34391854發表於2012-08-08

                           C++/C學習筆記(七)

1.聯合(union

聯合也是一種構造資料型別,它提供了一種使不同成員之間共享儲存空間的方法,同時可以實現不同型別資料成員之間的自動型別轉換。但與結構不同的是,聯合物件在同一時間只能儲存一個成員的值(即只有一個資料是活躍的)。

聯合的記憶體大小取決於其中位元組數最多的成員,而不是累加,聯合也會進行字長對齊,與位域不同的是,使用聯合不會帶來任何額外的執行時開銷。聯合中儲存的資料的值完全取決於對它的解釋方式。在定義聯合變數時可以指定初始值,但是隻能指定一個初始值,而且該初始值的型別必須與聯合的第一個成員的型別匹配。可以取一個聯合變數的地址,等同於其任一成員的地址。

可以在同型別的聯合變數之間賦值,但是不能比較兩個聯合變數的大小,不只是因為可能存在填補位元組,而且這兩個變數可能儲存著不同型別的成員,因此它們實際上代表兩個型別不同的變數。

C++Cunion進行了擴充套件,除了資料成員外還可以定義成員的訪問說明符,可以定義成員函式,建構函式和解構函式。但是聯合不能包含虛擬成員函式和靜態資料成員,不能作為其他型別的基類或者派生自其他型別。C++還支援匿名聯合。

比如定義一個用於社會中的“人”的型別,並且假設不會同時使用身份證號碼和姓名,就可以定義如下:

#include<cassert>

#include<iostream>

#include<iomanip>

using namespace std;

class Person{

public:

Person():type(true){id.ID=0;}

void SetID(unsigned long double newId){

id.ID=newId;

type=true;

}

unsigned long double GetID()const{

assert(type!=false);

return id.ID;

}

void SetName(const char* name){

strcpy(id.name,name);

type=false;

}

const char* GetName() const {

assert(type!=false);

return id.name;

}

bool IDIsSelected() const {return type;}

bool NameIsSelected()const {return (!Type);}

private:

union Choice

{

unsigned long ID; //身份證號碼

char name[20]; //姓名

};

Choice id; //ID/name

bool type; //標識當前存放的是ID(true)還是name(false)

};

int main(int argc,char* argv[])

{

Person p1;

p1.SetID(123456);

cout<<p1.GetID()<<endl;

p1.SetName("HYQ");

cout<<p1.GetName()<<endl;

if(p1.NameIsSelected())

cout<<"Now,id is type of name."<<endl;

else

cout<<"Now,id is type of ID."<<endl;

return 0;

}

輸出:

123456

HYQ

Now,id is type of name.

聯合的另一個妙用就是用來解析一個暫存器或多位元組記憶體變數的高低位元組的值,而不用我們手工使用位運算子來解析它們。

 

2.列舉(Enum

C++/C列舉型別允許我們定義特殊用途的一組符號常量,它表明這種型別的變數可以取值的範圍。當定義一個列舉型別的時候,如果不特別指定其中識別符號的值,則第一個識別符號的值將為0,後面的識別符號比前面的識別符號依次大1;若指定了其中某一個識別符號的值,那麼它後面的識別符號自動在前面的識別符號值的基礎上依次加1,除非同時還指定了它們的值。例如:

enum Week {Sun, Mon=125, Tue, Wed, Thu=140, Fri, Sat};

則列舉型別Week中各符號常量的值依次為0125126127140141142

列舉變數和常量都可以參與整型變數能夠參與的某些運算,但不能用列舉變數賦予一個不在列舉常量列表中的值,不要使用++--+=-=等操作,除非你特別為它過載了這些運算子。

列舉型別變數一般可以直接轉換成某種整數型別,除非其值超出了這種整數型別可以表示的範圍。但是一個整型變數在強制轉換成列舉型別後就不一定具有一個有效的值了,因為整型數是連續的,而列舉變數的取值很可能是不連續的。

列舉型別還可以是匿名的,匿名的列舉型別就相當於直接定義的const符號常量,可以作為全域性列舉,也可以放在任何類定義或名字空間中。

 

3.檔案

檔案操作屬於一種I/O操作,通過標準的I/O函式庫來實現。

任何物件和檔案只有與具體的應用相關聯才有含義,否則就是一些單純的位元組序列。也就是說,並不存在一種固定的“檔案記錄”,任何有意義的檔案格式都是由具體的應用領域決定的。

C++/C中,檔案操作是通過和“流”這種物件關聯而進行的,流即為位元組流。當開啟一個檔案的時候,作業系統就建立一個流物件並與該檔案關聯。作業系統維護了一個儲存當前系統中所有開啟檔案的檔案控制塊(FCB)的陣列,並利用每一個FCB來管理對每一個檔案的操作,陣列的上限就是作業系統允許你同時開啟的檔案個數的上限。

C語言中,首先宣告一個FILE結構的指標,然後呼叫庫函式fopen()fopen()動態建立一個FILE結構物件並分配一個檔案控制程式碼,從磁碟檔案中讀入FCB結構並填入FCB陣列中,然後返回這個FILE結構的地址。此後就可以拿著這個地址呼叫檔案操作庫函式來完成特定的任務。最後呼叫fclose()函式銷燬動態建立的FILE結構物件,同時釋放檔案控制程式碼並重新整理緩衝區。

C++實現了物件導向的I/O系統,不再讓使用者直接使用“檔案指標”這種原始的設施,而是把任何檔案看做一個物件,對該物件的操作就是在對一個檔案進行操作,同時允許使用者為自定義資料型別定製I/O操作。

相關文章