1. 程式人生 > >靜態成員資料 靜態物件初始化 .

靜態成員資料 靜態物件初始化 .

1.靜態成員資料的定義,與靜態型別的變數的定義方式一樣,要在成員資料的定義之前加關鍵字static。

2.靜態成員資料必須有確定的值,但由於在類的定義中不能對成員資料直接進行初始化,故必須在類定義的外部對靜態成員資料再宣告一次,並進行初始化,此時,前面不需要加關鍵字static。同時為了保持靜態成員資料取值的一致性,一般在類的建構函式中不給靜態成員資料設定初值。對靜態成員資料初始化的順序為它們在類體外宣告的順序.

3.在同一個程式中,當一個類有多個物件時,則這些物件中的靜態成員資料都共享同一個儲存空間,即在定義類時,就為靜態成員資料分配儲存單元,以後建立該類的物件時,將不再為該靜態成員資料分配儲存單元,也不會對該靜態成員資料初始化。

靜態成員資料初始化格式:

<型別><類名> ::<靜態成員資料> = <數值> ;

4.類的靜態成員資料具有全域性變數的某些特徵,比如在程式開始執行時就為靜態成員資料分配儲存空間,但它只有類的作用域。即在執行main()之前,首先對靜態成員資料和全域性變數分配儲存空間並進行初始化,當整個程式結束時才撤消靜態成員資料和全域性變數。

5.靜態成員資料也可以分為公有的、私有的和受保護的靜態成員。

對公有靜態成員,即可以通過類的物件進行訪問,也可以通過類名直接訪問(這是靜態成員資料與一般成員資料的另一個區別)。格式:

<類名>::<靜態成員資料>

私有的和保護的靜態成員資料則只能被該類的公有成員函式訪問。

6.值得注意的是,在建立任何物件之前,類的靜態成員資料已經存在並可以引.

7.靜態成員資料也可以是使用者自定義型別的資料。

1.2靜態成員函式

1.定義靜態成員函式時,只要在成員函式名前用關鍵字static修飾即可。

2.靜態成員函式屬於整個類,它是由該類的所有物件所共享的成員函式,它不屬於某個物件。因此它不含有隱含的*this指標引數,故它不能像普通成員函式那樣直接訪問物件中的非靜態的成員(成員函式和成員資料),即

靜態成員函式只能訪問所在類的靜態的成員(成員函式和成員資料)、全域性變數、外部函式等。(因為它們不屬於任一個特定物件)。

3。靜態成員函式若要訪問非靜態成員,則必須藉助於類的物件(物件名或指向物件的函式引數)。

4.靜態成員函式首先是一個成員函式,它可以定義為行內函數,也可以在類體外定義,但此時函式名前不必加關鍵字static.

5.可以通過所在類的物件訪問靜態成員函式(公有的)外,還可以通過類名直接訪問,格式為:

   <類名>::<靜態成員函式名>(<實參表>)

6.靜態成員函式不能為const成員函式。

例1   靜態成員資料的定義及應用

# include <iostream.h>

# include<stdlib.h>

class CCounter

{   static int count ;      //定義靜態成員資料

int objnumber ;       //表示物件編號

public :

CCounter( )

{ count ++ ; objnumber=count ; }

void Show ( )

{ cout<<”obj”<<objnumber<<’/t’<<”count=”<<count<<’/n’ ;}

} ;

int CCounter::count=0 ; //A 在類定義外宣告靜態成員資料並初始化,如果不賦初值,

//可以不賦初值,此時系統會自動賦初值0。

void main ( )

{ CCounter obj 1;

obj1.Show( ) ;

cout<<”----------------------/n “ ;

CCounter obj2 ;

obj1.Show ( ) ;

obj2.Show( ) ;

cout<<”----------------------/n “ ;

CCounter obj3 ;

obj1.Show ( ) ;

obj2.Show ( ) ;

obj3.Show ( ) ;

}

執行結果:

obj1    count=1

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

obj1    count=2

obj2    count=2

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

obj1    count=3

obj2    count=3

obj3    count=3

得注意的是,在建立任何物件之前,類的靜態成員資料已經存在並可以引用。

例2 分析程式輸出的結果

類的靜態成員資料具有全域性變數的某些特徵,在執行main()之前,首先對靜態成員資料和全域性變數分配儲存空間並進行初始化,當整個程式結束時才撤消靜態成員資料和全域性變數,但它只有類的作用域。

得注意的是,在建立任何物件之前,類的靜態成員資料已經存在並可以引用

# include <iostream.h>

class A

{    int i ;

   static int x ;

public :

   static int y ;

A ( int a , int b , int c )

{i=a , x=b , y =c ;}

void print ( )

{ cout<<”i=”<<i<<’/t’<<”x=”<<x<<’/t’<<”y=”<<y<<endl ;}

} ;

int A ::x=0 ;

int A ::y=0 ;

void main ( )

{count <<’y=”<<A ::y<<endl ; //B在建立任何物件之前,類中的靜態成員資料就已經存在

A a (11,22,33) ;

a.print () ;

A b(100 ,200 ,300) ;

a.print () ;

b.print () ;

A::y=400 ;                            //C,私有靜態成員資料不可以直接賦值。

b.print () ;

執行結果:

y=0

i=11    x=22    y=33

i=11    x=200   y=300

i=100   x=200   y=300

i=100   x=200   y=400

例: 靜態成員資料的生存期

靜態成員資料也可以是使用者自定義型別的資料。

#include<iostream.h>

class A

{ int i ;

public :

A (int x ){i=x ; cout<<”x=”<<i<<”/t 呼叫建構函式A() / n “ ;}

~ A( ){cout<<”x=”<<i<<” / t 呼叫解構函式~A()/ n” ;}

} ;

class B

{ static A a ;           宣告靜態成員資料

   static A c ;

public :

B ( ) {cout<<”呼叫建構函式B()/ n ”;}

~B ( ) {cout<<”呼叫解構函式~B()/ n ”;}

};

A B ::a (10) ;                //C 在類體外宣告靜態成員資料並初始化

A B ::c (5) ;                  //D

A a1 (20) ;                     //定義使用者自定義型別的全域性變數並初始化

void main ( )

{ cout<<”main()函式開始!/ n “ ;

B b ;

cout<<”main()函式結束!/ n “ ;

}

執行結果:

x=10   呼叫建構函式A()

x=5   呼叫建構函式A()

x=20   呼叫建構函式A()

main ( )函式開始

呼叫建構函式B()

main ( )函式結束

呼叫析造函式~B()

x=20   呼叫析造函式~A()

x=5   呼叫析造函式~A()

x=10   呼叫析造函式~A()

注意:

在執行main()之前,首先對靜態成員資料和全域性變數分配儲存空間並進行初始化,當整個程式結束時才撤消靜態成員資料和全域性變數。

對靜態成員資料初始化的順序為它們在類體外宣告的順序,如將C行和D行顛倒,則輸出的第1行和第2行將要顛倒,最後兩行也要顛倒。

例3: 靜態成員函式的定義和使用

# include <iostream.h>

void num_Show( ) ;

class CComputer

{ float price ;

static float total ;

public :

static int num ;   //建立物件的個數

CComputer ( float i)

{ price = i ;total+= i ;num++ ;}

void show ( )

{cout<<”The computer price is : “<<price<<endl ;}

static void t_show( )           //靜態成員函式

{ num_Show() ;

cout<<”total price is: “ <<total<<endl ;    //訪問靜態成員資料total

}

} ;

float CComputer::total=0 ;

int CComputer::num=0 ;

void num_Show( )        //輸出類CComputer靜態資料成員num

{cout<<”total number is: “<<CComputer::num<<endl ;}

void main ( )

{ CComputer ::t_show ( ) ;   //通過類名直接訪問靜態成員函式

CComputer c1(3500) ;

c1.show( );

c1.t_show( ) ;

CComputer c2(4500) ;

c2.show( ) ;

CComputer::t_show( ) ;        //A通過類名直接訪問靜態成員函式

}                           // c1.t_show( );c2.t_show( );

執行結果:

total number is: 0

total price is: 0

The computer price is : 3500

total number is: 1

total price is: 3500

The computer price is : 4500

total number is: 2

total price is: 8000

//A行通過類名訪問其中的公有靜態成員函式,該語句與如下任一語句等價:

c1.t_show( );

c2.t_show( );

例4: 在靜態成員函式中通過物件訪問類的非靜態成員

靜態成員函式可以直接呼叫所屬類的其他靜態成員,但不能直接訪問非靜態成員(成員函式和成員資料),若要訪問非靜態成員,則必須藉助於類的物件。

#include<iostream.h>

class A

{ int x ;

static int y;

public:

A (int x1 ,int x2)

{ x=x1 ; y=y+x2 ;}

static void show1( ) ;

static void show2(A a) ;

};

void A::show1( )

{ cout<<”y=”<<y<<endl ; }    //直接訪問靜態資料

void A::show2 ( A a)       //

{cout<<”x=”<< a . x <<” /t “<<”y=”<<y<<endl ;}

//{cout<<”x=”<<x<<” /t “<<”y=”<<y<<endl ;} //B 錯,不能直接訪問非靜態成員

int A::y=6 ;

void main( )

{ A a1(11 ,22) ;

a1.show1 ( ) ;         //通過物件名訪問

A::show2 ( a1) ;     //通過類名訪問

A a2(33,44) ;

A::show1( ) ;       //通過類名訪問

a2.show2(a2) ;        //   C通過物件名訪問

}

對C,可換用用a1.show2(a2) ;或A::show2(a2) ; //對show1() ;同理

執行結果:

y=28

x=11 y=28

y=72

x=33 y=72 。

例 7-6

z07p226L7-6

//program 7-6.cpp      

#include <iostream.h>

class claA

{ public:

       double x,y;

       static int num;     //公有靜態資料成員 -- 供所有物件“共享”

                     //用於記錄已通過建構函式生成了多少個物件。      

claA() {     

              x=0;       y=0;

              num++;       //每生成一個物件,num加1

       }

       claA(double x0, double y0) {

              x=x0;      y=y0;

              num++;

       }

       static void staFun()          //靜態函式成員,輸出靜態資料成員num的當前值

{     cout<<"current_num="<<num<<endl;    }

};

int claA::num=0;     //必須在類外(使用類名限定)初始化靜態資料成員

void main()

{      claA obj(1.2, 3.4), *p;

       cout<<"claA::num="<<claA::num<<”/t” ;

       claA::staFun();

       cout<<"obj.num="<<obj.num<”/t”;

       obj.staFun();

       claA A[3];           //說明具有3個物件的陣列,將三次呼叫其建構函式

       cout<<"claA::num="<<claA::num<<”/t”;

       claA::staFun();    

p = new claA(5.6, 7.8);     生成動態物件*p,將呼叫建構函式

       cout<<"claA::num="<<claA::num<<”/t”;

       claA::staFun();

       cout<<"p->num="<<p->num<<”/t”;

       p->staFun();

}

        程式執行後,螢幕顯示結果為:

claA::num=1        current_num=1

obj.num=1            current_num=1

claA::num=4        current_num=4

claA::num=5        current_num=5

p->num=5            current_num=5

注意:

      將claA類中的資料成員x、y以及num都說明為public公有型的,是為了在主調函式main中可以直接存取它們而使程式簡單化,否則(對非公有型的資料成員),在類外存取它們時還要設立類似於getx()那樣的公有成員函式。