C++類與static關鍵字

到目前爲止,我們設計的類中所有的成員變量和成員函數都是屬於對象的,如我們在前面定義的book類,利用book類聲明兩個對象Alice和Harry,這兩個對象均擁有各自的price和title成員變量,同時還擁有類中所有的成員函數。

除了這種情況以外,我們還有另外一種類型的成員,那就是與static結合的成員變量和成員函數。類中的成員變量或成員函數一旦與static關鍵字相結合,則該成員變量或成員函數就是屬於類的,而不是再是屬於任何一個對象的,當然任何一個對象都可以共享該成員變量及成員函數。

靜態成員變量

靜態成員變量聲明非常簡單,只需要將static關鍵字加在成員變量聲明的前面即可,如例1所示,我們在例中聲明瞭一個靜態成員變量count,並將其設置爲private屬性。設計這個count變量主要是爲了統計當前存活的student類對象的個數,當然這個類並不完善,通過這個例子,我們可以瞭解靜態成員變量的聲明語法。

例1:

class student
{
public:
    student(){count ++;}
    ~student(){count --;}
private:
    static int count;
    //其它成員變量
};

靜態成員變量在類內部聲明之後還需要進行定義操作。

例2:

class student
{
public:
    student(){count ++;}
    ~student(){count --;}
private:
    static int count;
    //其它成員變量
};
int student::count = 0;

請仔細查看例2的代碼,這段代碼雖然與例1相比只是增添了一行代碼,卻是有幾處需要我們特別留心。首先靜態成員變量的定義必須在任何程序塊之外;其次調用該變量的時候可以直接用類名加上域解析符“::”加上變量名的形式,這是靜態成員變量特有的引用方式;在類外部進行定義的時候static關鍵字是不需要的。

在C++語法中規定靜態成員變量會被默認初始化爲0,類外定義可有可無。而實際上在一些編譯器中,如果不加上類外的定義,會出現一些不可知的情況,故在實際設計程序的時候最好還是將類外定義加上。

靜態成員變量不會影響類及其對象的大小,也即sizeof結果不會受到影響。在上面的例2中,無論我們是否聲明count這個靜態成員變量,sizeof(student)或者sizeof(student的對象)其結果都是不會變的。

靜態成員變量屬於類而不屬於任何一個對象,如此一來可以實現數據共享功能,如例3所示。

例3:

#include<iostream>
using namespace std;
class test
{
public:
    static int num;
};
int test::num = 1;
int main()
{
    test one;
    test two;
    test three;
    cout<<test::num<<" "<<one.num<<" "<<two.num<<" "<<three.num<<endl;
    test::num = 5;
    cout<<test::num<<" "<<one.num<<" "<<two.num<<" "<<three.num<<endl;
    one.num = 8;
    cout<<test::num<<" "<<one.num<<" "<<two.num<<" "<<three.num<<endl;
    two.num = 4;
    cout<<test::num<<" "<<one.num<<" "<<two.num<<" "<<three.num<<endl;
    three.num = 2;
    cout<<test::num<<" "<<one.num<<" "<<two.num<<" "<<three.num<<endl;
    return 0;
}

程序運行結果:
1 1 1 1
5 5 5 5
8 8 8 8
4 4 4 4
2 2 2 2

在本例中,爲了方便樣式static成員變量的共享特性,我們將靜態成員變量設爲public屬性,如此一來在類外可以方便調用。在類外我們先將靜態成員變量進行定義,並初始化爲1。在主函數中我們爲test類定義了三個對象,分別爲one、two和three。之後分別用類名和對象名調用該靜態成員變量修改其值,並各自調用的結果打印出來。從程序運行結果可以看出,四種調用靜態成員變量的方法,其值都是相等的,如果其中有任何一個修改該靜態成員變量,所有其他的調用靜態成員變量都會跟着一起改變。這就是靜態成員變量的共享特性,靜態成員變量不屬於任何對象,但是可以通過對象訪問靜態成員變量。靜態成員變量屬於類,因此可以通過類來調用靜態成員變量。靜態成員變量如果被設置爲private或protected屬性,則在類外同樣無法訪問,但定義該變量的時候卻不受此限制,如例2所示,雖然靜態成員變量count爲private屬性,但是它在類外定義的時候不受private限制。

靜態成員函數

在類內除了能用static聲明靜態成員變量外,同樣可以使用static聲明靜態成員函數,靜態成員函數只能訪問static成員變量。

例4:

#include<iostream>
using namespace std;
class test
{
public:
        test(int a, int b){num = a; plus = b;}
    static int getnum(){return num;}
    static int add(){return num+plus;}  //compile error
    void setnum(int a){num = a;}
    void setplus(int a){plus = a;}
private:
    static int num;
    int plus;
};
int test::num = 1;
int main()
{
    test one;
    one.setnum(5);
    cout<<test::getnum()<<endl;
    return 0;
}

在本例程中,類test內有一個靜態成員變量num,一個普通成員變量plus,這兩個變量都是private屬性,成員函數有一個構造函數,兩個普通成員函數和兩個靜態成員函數。在構造函數中,我們引用了靜態成員變量num,這是允許的,同樣在setnum函數中,同樣引用了靜態成員變量num,這個也是允許的。然而在add函數中我們不僅引用了靜態成員變量num,同時還訪問了非靜態成員變量plus,而這是不允許的。靜態成員函數只能訪問靜態成員變量,而不能訪問非靜態成員變量。普通成員函數(包括構造函數和析構函數)既可以訪問普通成員變量,同時又可以訪問靜態成員變量。

訪問靜態成員變量和靜態成員函數均有兩種方式,其一是和普通的成員變量成員函數相同,通過對象來訪問,其二則是可以通過類名加上域解析操作符訪問。當然訪問過程中仍然要遵循private、protected和public關鍵字的訪問權限限定。訪問靜態成員變量和靜態成員函數首選的方法是通過類來訪問,畢竟靜態成員變量和靜態成員函數都是屬於類的,與類相關聯,而不是屬於類的對象。普通成員變量或成員函數不可以通過類來訪問。由於靜態成員變量和靜態成員函數都是屬於類,而不是屬於對象,因此靜態成員函數內部也不存在this指針,因爲靜態成員函數不屬於對象。

在靜態成員函數內部可以聲明靜態變量,注意不是靜態成員變量。如果在靜態成員函數內部聲明一個靜態變量,則該類的所有對象將共享這個變量。

例5:

#include<iostream>
using namespace std;
class test
{
public:
    static void add(int a);
};
void test::add(int a)
{
    static int num = 0;
    int count = 0;
    num += a;
    count += a;
    cout<<num<<" "<<count<<endl;
}
int main()
{
    test one,two,three;
    one.add(5);
    two.add(4);
    three.add(11);
    return 0;
}

程序運行結果:
5 5
9 4
20 11

爲了直截了當地說明這個問題,我們只在類test中聲明瞭一個靜態成員函數add,並且在類外對這個函數進行了定義。注意,在類外定義靜態成員函數是不需要static關鍵字的。在add函數內部我們定義了一個靜態變量num,並且初始化爲0,爲了增強對比效果,我們又定義了一個普通的變量count。在主函數中定義了三個變量,分別調用靜態成員函數,結果num值打印結果是累加的,而count則每次都是從0開始的,並不是累加的。通過對比我們很容易看出,static是被這三個對象同時共享的,三個對象一份數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章