c++ 靜態數據成員和靜態成員函數

 

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

  本例創建了靜態的成員變量size,靜態的數組成員table和letters。靜態的數組成員的初始化方法與數組的初始化類似,但要有類名和作用域分隔符限制。

成員常量   

我們先看下面一個實例:  

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

 

 

嵌套類和局部類中靜態成員變量的使用  

可以很容易地把一個靜態數據成員放在一個嵌套類中,它是非嵌套類中靜態數據成員情況的擴展,只將它的範圍進行另一個級別的指定就可以了。然而,在局部類(如在函數內部定義的類)中不能有靜態數據成員。例如:

例題 例10-21
 

// Nested class CAN have static data members:

class outer

{

 class inner

 {

  static int i; //OK

 };

};

int outer::inner::i = 100;

// Local class CANNOT have static data members:

void f()

{

 class local

 {

  static int i; //error

 };

}

void main(){}

 

轉:http://hi.baidu.com/%B8%C7%CA%C0%D0%A1%B3%E6/blog/item/4103f845a531ea35879473a0.html

 

------------------------------------------------------------------------------------------------------------------------------------

2、 靜態成員函數

 

靜態成員函數:靜態成員函數一般只能訪問靜態成員變量,如果要訪問非靜態成員變量的話,只能訪問某一個對象的非靜態成員變量和靜態成員函數。可以傳一個對象的指針,引用等參數給這個靜態成員函數。

   

     靜態成員函數中是不能調用非靜態成員的,包括非靜態成員函數和非靜態成員變量。那麼在非靜態成員函數中是否可以調用靜態成員函數呢?答案是肯定的,因爲靜態成員函數屬於類本身,在類的對象產生之前就已經存在了,所以在非靜態成員函數中是可以調用靜態成員函數的。其實,我們也可以以一個內存模型這個角度來考慮,也就是說,無論採取什麼樣的操作,程序代碼都是在內存中運行的,只有在內存中佔有了一席之地,我們才能訪問它。如果一個成員函數或成員變量還沒有在內存中產生,結果是無法訪問它的。所有靜態成員函數只能訪問靜態成員變量。

使用static關鍵字聲明的函數成員使靜態的,靜態成員函數同樣也屬於整個類,由同一個類的所有對象共同維護,爲這些對象所共享. 
作爲成員函數,它的訪問屬性可以受到類的嚴格控制,對於公有的靜態函數成員函數,可以通過類名或對象名來調用,但一般情況下建議用對象名來引用靜態函數成員.注意,一般的成員函數只能通過對象名來調用. 
由於一個類的靜態成員函數只有一個拷貝,因此它訪問對象的數據和函數時受到了限制.靜態成員函數可以直接訪問該類的靜態數據成員.而訪問非靜態數據成員, 必須通過參數傳遞方式得到對象名,然後通過對象名來訪問.可以看到,通過靜態函數成員訪問非靜態成員使相當麻煩的,一般的使用中,它主要用來訪問全局變量或同一個類中的靜態數據成員,特別是和後者一起使用,達到對同一個類中對象之間共享的數據進行維護的目的. 
構造函數和析構函數不可以定義爲static,構造函數要給每一個對象一個this指針如果可以是靜態的,它如何構造和訪問this指針?
明顯是不可以的!

      靜態成員變量一般要在.cpp文件裏進行定義:double Account::_interestRate = 0.0589;靜態成員函數的聲明除了在類體中的函數聲明前加上關鍵字static 以及不能聲明爲const 或volatile 之外與非靜態成員函數相同,出現在類體外的函數定義不能指定關鍵字static.

 

轉自http://hi.baidu.com/mwc1586/blog/item/470a1a353e633140251f14ea.html

 

 

發佈了18 篇原創文章 · 獲贊 27 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章