天天看點

C++ 進階資料類型(六)—— 自定義資料類型

前面我們已經看到過一種使用者(程式員)定義的資料類型:結構。除此之外,還有一些其它類型的使用者自定義資料類型:

定義自己的資料類型 (typedef)

C++ 允許我們在現有資料類型的基礎上定義我們自己的資料類型。我們将用關鍵字typedef來實作這種定義,它的形式是:

typedef existing_type new_type_name;

這裡 existing_type 是C++ 基本資料類型或其它已經被定義了的資料類型,new_type_name 是我們将要定義的新資料類型的名稱。例如:

typedef char C;

typedef unsigned int WORD;

typedef char * string_t;

typedef char field [50];

在上面的例子中,我們定義了四種新的資料類型: C, WORD, string_t 和 field ,它們分别代替 char, unsigned int, char* 和 char[50] 。這樣,我們就可以安全的使用以下代碼:

C achar, anotherchar, *ptchar1;

WORD myword;

string_t ptchar2;

field name;

如果在一個程式中我們反複使用一種資料類型,而在以後的版本中我們有可能改變該資料類型的情況下,typedef 就很有用了。或者如果一種資料類型的名稱太長,你想用一個比較短的名字來代替,也可以是用typedef。

聯合(Union)

聯合(Union) 使得同一段記憶體可以被按照不同的資料類型來通路,資料實際是存儲在同一個位置的。它的聲明和使用看起來與結構(structure)十分相似,但實際功能是完全不同的:

union model_name {

    type1 element1;

    type2 element2;

    type3 element3;

    .

    .

} object_name;

union 中的所有被聲明的元素占據同一段記憶體空間,其大小取聲明中最長的元素的大小。例如:

union mytypes_t {

    char c;

    int i;

    float f;

} mytypes;

定義了3個元素:

mytypes.c mytypes.i mytypes.f

每一個是一種不同的資料類型。既然它們都指向同一段記憶體空間,改變其中一個元素的值,将會影響所有其他元素的值。

union 的用途之一是将一種較長的基本類型與由其它比較小的資料類型組成的結構(structure)或數組(array)聯合使用,例如:

union mix_t{

    long l;

    struct {

        short hi;

        short lo;

    } s;

    char c[4];

} mix;

以上例子中定義了3個名稱:mix.l, mix.s 和 mix.c,我們可以通過這3個名字來通路同一段4 bytes長的記憶體空間。至于使用哪一個名字來通路,取決于我們想使用什麼資料類型,是long, short 還是 char 。下圖顯示了在這個聯合(union)中各個元素在記憶體中的的可能結構,以及我們如何通過不同的資料類型進行通路:

C++ 進階資料類型(六)—— 自定義資料類型

匿名聯合(Anonymous union)

C++ 進階資料類型(六)—— 自定義資料類型

在 C++ 我們可以選擇使聯合(union)匿名。如果我們将一個union包括在一個結構(structure)的定義中,并且不賦予它object名稱 (就是跟在花括号{}後面的名字),這個union就是匿名的。這種情況下我們可以直接使用union中元素的名字來通路該元素,而不需要再在前面加 union對象的名稱。在下面的例子中,我們可以看到這兩種表達方式在使用上的差別:

union anonymous union

struct {

    char title[50];

    char author[50];

    union {

        float dollars;

        int yens;

    } price;

} book;

struct {

    char title[50];

    char author[50];

    union {

        float dollars;

        int yens;

    };

} book;

以上兩種定義的唯一差別在于左邊的定義中我們給了union一個名字price,而在右邊的定義中我們沒給。在使用時的差別是當我們想通路一個對象(object)的元素dollars 和yens 時,在前一種定義的情況下,需要使用:

book.price.dollars book.price.yens

而在後面一種定義下,我們直接使用:

book.dollars book.yens

再一次提醒,因為這是一個聯合(union),域dollars 和yens 占據的是同一塊記憶體空間,是以它們不能被用來存儲兩個不同的值。也就是你可以使用一個dollars 或yens的價格,但不能同時使用兩者。

枚舉Enumerations (enum)

枚舉(Enumerations)可以用來生成一些任意類型的資料,不隻限于數字類型或字元類型,甚至常量true 和false。它的定義形式如下:

enum model_name {

    value1,

    value2,

    value3,

    .

    .

} object_name;

例如,我們可以定義一種新的變量類型叫做color_t 來存儲不同的顔色:

enum colors_t {black, blue, green, cyan, red, purple, yellow, white};

注意在這個定義裡我們沒有使用任何基本資料類型。換句話說,我們創造了一種的新的資料類型,而它并沒有基于任何已存在的資料類型:類型color_t,花括号{}中包括了它的所有的可能取值。例如,在定義了colors_t 列舉類型後,我們可以使用以下表達式 :

colors_t mycolor;

mycolor = blue;

if (mycolor == green) mycolor = red;

實際上,我們的枚舉資料類型在編譯時是被編譯為整型數值的,而它的數值清單可以是任何指定的整型常量 。如果沒有指定常量,枚舉中第一個列出的可能值為0 ,後面的每一個值為前面一個值加1。是以,在我們前面定義的資料類型colors_t 中,black 相當于0, blue 相當于 1, green 相當于2 ,後面依此類推。

如果我們在定義枚舉資料類型的時候明确指定某些可能值(例如第一個)的等價整數值,後面的數值将會在此基礎上增加,例如:

enum months_t { january=1, february, march, april,
                may, june, july, august,
                september, october, november, december} y2k;      

在這個例子中,枚舉類型months_t的變量y2k 可以是12種可能取值中的任何一個,從january 到 december ,它們相當于數值1 到 12,而不是0 到 11 ,因為我們已經指定 january 等于1。