1 靜態數據成員
要定義靜態數據成員,只要在數據成員的定義前增加static關鍵字。靜態數據成員不同於非靜態的數據成員,一個類的靜態數據成員僅創建和初始化一次,且在程序開始執行的時候創建,然後被該類的所有對象共享;而非靜態的數據成員則隨着對象的創建而多次創建和初始化。下面是靜態數據成員定義的例:
例10-18 | |
class Test { public: static int public_int; private: static int private_int; }; void main() { Test::public_int = 145; // 正確 Test::private_int = 12; // 錯誤,不能訪問私有的數據成員 } |
|
從上例我們可以看到:靜態數據成員的訪問方式是:類名::靜態數據成員名但是,不能直接訪問私有的數據成員。其實,上面的程序段只是爲了介紹如何訪問靜態數據成員,不能通過編譯器的的編譯和連接。
一、私有的靜態數據成員
爲了說明私有的靜態數據成員的使用,考慮下面的程序段:
class Directory
{
public: ...
private:
// 數據成員
static char path[];
};
數據成員path[]是一個私有的靜態變量,在程序執行過程中,僅一個Directory::path[]存在,即使有多個Directory類的對象。靜態的數據成員能夠被類的成員函數訪問,但不能在構造函數中初始化。這是因爲靜態數據成員在構造函數被調用之前就已經存在了。靜態數據成員可以在定義時初始化,且必須在類和所有的成員函數之外,與全局變量初始化的方法一樣。例如,類Directory的數據成員的定義與初始化方法如下:
// 靜態數據成員的定義與初始化
char Directory::path [200] = "/usr/local";
// 無參的構造函數
Directory::Directory()
{ ... }
在類中的靜態數據成員的定義,只是說明該類有這麼一個數據成員,並沒有爲該數據成員分配內存。就象非靜態數據成員是在創建對象時分配內存一樣,靜態數據成員是在初始化時分配內存的。所以,在定義靜態的數組成員時,可以省略它的尺寸(數組元素的個數),但在初始化時,必須確定數組的尺寸。
二、公有的靜態數據成員
數據成員也可以是公有的,不過我們很少定義公有的數據成員,因爲它破壞了數據隱藏的原則。如果Directory類的成員path[]定義爲公有的,則該成員可在類外的任一地方訪問:
void main()
{
strcpy(Directory::path, "/usr/local/pub"); //修改path的值
…
}
path仍然必須先初始化:
char Directory::path[200];
爲什麼需要靜態數據成員?
類的靜態數據成員擁有一塊單獨的存儲區,而不管我們創建了多少個該類的對象。也就是說,靜態數據成員被類的所有對象共享,它是屬於類,而不是屬於對象的。所有對象的靜態數據成員都共享一塊靜態存儲空間,可以節省內存,也爲對象之間提供了一種互相通信的方法。靜態數據成員的作用域在類內,也有public(公有)、private(私有)或者protected(保護)三種訪問權限。 靜態數據成員的存儲空間分配 對於非靜態數據成員而言,有多少個對象,就有多少個不同的內存單元,它們分佈在各個對象的存儲空間中。靜態數據成員不同於非靜態數據成員,不管有多少個對象,它們都共享相同的內存單元。所以,靜態數據成員不應該屬於任何一個對象,說它屬於類更確切。
我們用一個例子來說明這種存儲空間的關係, 對於類:
class C
{
static int si;
static int sc;
int i;
char c;
……
};
如果我們創建了類C的三個對象c1、c2和c3,那麼它們的數據成員的存儲關係如圖10-2所示:
圖10-2 | |
靜態數據成員的初始化必須在類外,例如:
class A
{
public:
static int i; //……
};
靜態數據成員i的初始化方法爲:
int A::i=1;
可見:它與全局變量的初始化的方法的不同之處在於,有類名和作用域分隔符指定i的範圍。
我們還可以定義靜態的數組成員,例如:
例10-19 | |
class Values { private: static const int size; static const float table[4]; static char letters[5]; }; const int Values::size = 100; const float Values::table[4] = {1.1, 2.2, 3.3, 4.4}; char Values::letters[5] = {'a', 'b', 'c', 'd', 'e'}; void main(){} |
|
成員常量
我們先看下面一個實例:
class A
{
const size = 100; //illegal
int array[size]; //illegal
};
類A是想定義一個常量數組,但這個類的定義是錯誤的。因爲定義類常量數據成員時,不能同時進行初始化。定義類時,只是說明類有那些數據成員,而不涉及到內存單元的分配,類數據成員存儲單元的分配是在對象初始化時進行的。 我們也可以把常量數據成員定義成靜態的,同靜態成員變量初始化一樣,靜態成員常量初始化也在類外,
例如:
例10-20 | |
class A { static const int size; int array[size]; public: // ... }; const int A::size = 100; //definition
|
嵌套類和局部類中靜態成員變量的使用 可以很容易地把一個靜態數據成員放在一個嵌套類中,它是非嵌套類中靜態數據成員情況的擴展,只將它的範圍進行另一個級別的指定就可以了。然而,在局部類(如在函數內部定義的類)中不能有靜態數據成員。例如:
|