c++類的靜態成員,建構函式
一、靜態成員
靜態成員是處理同一個類的不同物件之間資料和函式共享問題的。
1.靜態資料成員
我們所說的“一個類的所有物件具有相同的屬性”是指例項屬性,以非靜態資料成員表示,如Employee中的empNo.id.它們在類的每一個物件中都具有一個複本,是每個物件區別於其他物件的特徵。如果某個屬性為整個類所共有(如:僱員總數)不屬於任何一個具體物件,則採用static關鍵字來宣告為靜態成員。
靜態成員在每個類中只有一個副本,由該類所有物件共同維護和使用,從而實現同一類的不同物件之間的資料共享。
靜態資料成員具有靜態生存期。通過類名對其訪問“類名::識別符號”。
在類中的定義僅僅對靜態資料成員進行引用性宣告,必須在名稱空間作用域的某個地方使用類名限定定義性宣告,靜態資料成員的定義和初始化在類外進行,以此法為它們分配空間。
#include <iostream>
using namespace std;
class Point{
public:
Point(int x=0,int y=0):x(x),y(y){
count++;//在建構函式中對count累加,所有物件共同維護同一個count
}
Point(Point &p){//複製建構函式
x=p.x;
y=p.y;
count++;
}
~Point(){count--;}
int getX(){return x;}
int getY(){return y;}
void showCount(){//輸出靜態資料成員
cout<<" Object count="<<count<<endl;
}
private:
int x,y;
static int count;//靜態資料成員宣告,用於記錄點的個數
};
int Point::count=0;//靜態資料成員定義和初始化,使用類名限定
int main()
{
Point a(4,5);
cout<<"Point A: "<<a.getX()<<","<<a.getY();
a.showCount();
Point b(a);
cout<<"Point B: "<<b.getX()<<","<<b.getY();
b.showCount();
return 0;
}
結果:
Point A: 4,5 Object count=1
Point B: 4,5 Object count=2
2.靜態函式成員
靜態函式成員即使用static關鍵字宣告的函式成員,屬於整個類,由同一個類的所有物件共有,為這些物件所共享。
靜態成員函式可以通過類名或物件名來呼叫,而非靜態成員函式只能通過物件名來呼叫。
靜態成員函式可以直接訪問該類的靜態資料和函式成員,而訪問非靜態成員必須通過物件名。
#include <iostream>
using namespace std;
class Point{
public:
Point(int x=0,int y=0):x(x),y(y){
count++;//在建構函式中對count累加,所有物件共同維護同一個count
}
Point(Point &p){//複製建構函式
x=p.x;
y=p.y;
count++;
}
~Point(){count--;}
int getX(){return x;}
int getY(){return y;}
static void showCount(){
cout<<" Object count="<<count<<endl;
}
private:
int x,y;
static int count;//靜態資料成員宣告,用於記錄點的個數
};
int Point::count=0;//靜態資料成員定義和初始化,使用類名限定
int main()
{
Point a(4,5);
cout<<"Point A: "<<a.getX()<<","<<a.getY();
Point::showCount();
Point b(a);
cout<<"Point B: "<<b.getX()<<","<<b.getY();
Point::showCount();
return 0;
}
結果:
Point A: 4,5 Object count=1
Point B: 4,5 Object count=2
二、研究C語言typedef語句和巨集的用法,以及在寫Win32 API程式過程中的用途
1、typedef的用法
在C/C++中,typedef常用來定義一個識別符號及關鍵字的別名,它是語言編譯過程的一部分,但它並不實際分配記憶體空間,例項像:
typedef int INT;
typedef int ARRAY[10];
typedef (int*) pINT;
typedef可以增強程式的可讀性,以及識別符號的靈活性,但它也有“非直觀性”等缺點。為了增加可讀性為識別符號起的新名稱。
2、#define的用法
#define為巨集定義語句,通常用它來定義常量(包括無參量與帶參量),以及用來實現那些“表面似和善、背後一長串”的巨集,它本身並不在編譯過程中進行,而是在這之前(預處理過程)就已經完成了,但也因此難以發現潛在的錯誤及其它程式碼維護問題,它的例項像:
#define INT int
#define TRUE 1
#define Add(a,b) ((a)+(b));
#define Loop_10 for (int i=0; i<10; i++)
巨集定義只是簡單的字串代換(原地擴充套件),而typedef則不是原地擴充套件,它的新名字具有一定的封裝性,以致於新命名的識別符號具有更易定義變數的功能。
三、建構函式
建構函式的作用就是在物件被建立時利用特定的值構造物件,將物件初始化為一個特定的狀態。
建構函式的函式名與類名相同,而且沒有返回值。
建構函式在物件被建立時被自動呼叫。呼叫時無需提供引數的建構函式稱為預設建構函式。如果類中沒有寫建構函式,編譯器會自動生成一個隱含的預設建構函式,該建構函式的引數列表和函式體皆為空。
複製建構函式是一種特殊的建構函式,具有一般建構函式的所有特性,其形參是本類的物件的引用。其作用是使用一個已經存在的物件(由複製建構函式的引數指定),去初始化同類的一個新物件。
#include <iostream>
using namespace std;
class Point //Point 類的宣告
{
public: //外部介面
Point(int xx=0, int yy=0) {X=xx;Y=yy;} //建構函式
Point(Point &p); //拷貝建構函式
int GetX() {return X;}
int GetY() {return Y;}
private: //私有資料
int X,Y;
};
//成員函式的實現
Point::Point(Point &p)
{
X=p.X;
Y=p.Y;
cout<<"Calling the copy constructor"<<endl;
}
//形參為Point類物件的函式
void fun1(Point p)
{ cout<<p.GetX()<<endl;
}
//返回值為Point類物件的函式
Point fun2()
{
Point A(1,2);
return A;
}
//主程式
int main()
{
Point A(4,5); //第一個物件A
Point B(A); //情況一,用A初始化B。第一次呼叫拷貝建構函式
cout<<B.GetX()<<endl;
fun1(B); //情況二,物件B作為fun1的實參。第二次呼叫拷貝建構函式
B=fun2(); //情況三,函式的返回值是類物件,函式返回時,呼叫拷貝建構函式
cout<<B.GetX()<<endl;
return 0;
}
四、行內函數
行內函數不是在呼叫時發生控制轉移,而是在編譯時將函式體嵌入在每一個呼叫處。
對於一些功能簡單,規模較小又使用頻繁的函式可以設計為行內函數
#include<iostream>
usingnamespace std;
classClock{
public:
voidsetTime(int newH=0,int newM=0,int newS=0);
voidshowTime();
private:
inthour,minute,second;
};
voidClock::setTime(int newH, int newM, int newS){
hour=newH;minute=newM;second=newS;
}
inlinevoid Clock::showTime(){//行內函數
cout<<hour<<":"<<minute<<":"<<second<<endl;
}
intmain()
{
ClockmyClock;
cout<<"Firsttime set and output:"<<endl;
myClock.setTime();
myClock.showTime();
cout<<"Secondtime set and output:"<<endl;
myClock.setTime(8,30,30);
myClock.showTime();
return0;
}