靜態成員資料 靜態物件初始化 .
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()那樣的公有成員函式。