1. 程式人生 > >C++程式設計(四)—— 類和物件

C++程式設計(四)—— 類和物件

一、類及其例項化

1、定義類

        類要先聲明後使用;不能宣告兩個名字相同的類,類是具有唯一識別符號的實體;在類中宣告的任何成員不能使用extern、auto、register關鍵字進行修飾;類中宣告的變數屬於該類,在某些情況下,變數也可以被該類的不同例項所共享;類中有資料成員和成員函式,不有在類宣告中對資料成員使用表示式進行初始化。

⑴ 宣告類

        宣告類以class開始,其後跟類名,類所宣告的內容用花括號括起來,右括號後的分號作為類宣告結束的標誌。

        類成員具有訪問許可權,通過它前面的關鍵字來定義,關鍵字private後的成員叫私有成員、public後的成員叫公有成員、protected後的成員叫受保護的成員,訪問許可權用於控制物件的成員在程式中的可訪問性。如果沒有使用關鍵字,則所有成員預設宣告為private許可權。

class Point{//類名Point
private://宣告為私有訪問許可權
	int x,y;//私有的資料成員

public://宣告為公有的訪問許可權
	void setXY(int a,int b);
	void move(int a,int b);
	void display();
	int getX();
	int getY();
};//宣告以分號為結尾

⑵ 定義成員函式

        類中宣告的成員函式用來對資料成員進行操作,還必須在程式中實現這些成員函式。

#include <iostream>
using namespace std;

class Point{//類名Point
private://宣告為私有訪問許可權
	int x,y;//私有的資料成員

public://宣告為公有的訪問許可權
    Point(){};//沒有引數的建構函式
    Point(int a,int b){//兩個有參的建構函式
		x = a;
		y = b;
	}
	void setXY(int a,int b);//函式宣告
	void display();
	inline int getX();//宣告為行內函數
	int getY(){//在類體中定義函式,如果不包含迴圈或switch語句則預設為行內函數
		return y;
	}
};//宣告以分號為結尾

//在類體外定義函式
void Point :: setXY(int a,int b){
	x = a;
	y = b;
}
void Point :: display(){
	cout << x << "," << y;
}
inline int Point :: getX(){//類體外定義行內函數
	return x;
}

        一般在類體中給出簡單成員函式的定義,在類中定義的函式如果不包含迴圈或switch語句會被系統預設當作行內函數來處理,函式體內容較多的函式則在類外定義,系統並不會把它們預設為行內函數,如果想把它們指定為行內函數,則應該使用inline進行顯示宣告。如果在類體外定義行內函數,需要把函式宣告和函式定義放在同個原始檔中才能編譯成功。

        在類體中直接定義函式時,不需要在函式名前加上類名,只有在類體外定義時才需要。其中,“::”是作用域運算子,它用於表明其後的成員函式是屬於這個特定的類 。

⑶ 資料成員的賦值

        不能在類體內給資料成員賦值,資料成員的具體值是用來描述物件屬性的,只有產生了一個具體的物件,這些資料值才有意義。如果產生物件時就使物件的資料成員具有指定值,則稱為物件的初始化。注意,初始化和賦初值是兩個不同的概念,初始化是使用與Point同名的建構函式來實現的,賦初值是在有了物件A之後,物件A呼叫自己的資料成員或成員函式實現賦值操作。

int main(){
	//建構函式初始化
	Point a(10,20);

	//物件賦值
	Point b;
	b.setXY(10,20);

	return 0;
}

2、使用類的物件

        只有產生類的物件,才能使用這些資料和成員函式。類不僅可以宣告為物件,還可以宣告為物件的引用和物件的指標。

//定義print函式的過載,分類使用類指標和類物件作為引數
void print(Point *a){//類指標作為引數過載print函式
	a -> display();
}
void print(Point &b){//類引用作為引數過載print函式
	b.display();
}
int main(){
	//建構函式初始化
	Point a(10,20);

	//物件賦值
	Point b;
	b.setXY(10,20);

	Point *p1 = &a;//宣告物件a的物件指標
	Point &p2 = b;//宣告物件b的物件引用

	print(p1);//10,20
	print(p2);//10,20

	return 0;
}

 總結:

① 類的成員函式可以直接使用類的私有成員;

② 類外的函式不能直接使用類的私有成員;

③ 類外的函式只能通過類的物件使用該類的公有成員函式;

④ 物件的成員函式程式碼都是一樣的,物件的區別只是屬性的取值;

⑤ 在程式執行時,通過為物件分配記憶體來建立物件,為了節省記憶體,在建立物件時,只分配用於儲存資料的記憶體,程式碼為每個物件共享,類中定義的程式碼被放在計算機內的一個公共區中供該類的所有物件共享;

⑥ 物件和引用在訪問物件的成員時,使用運算子“.”,而指標則使用“->”運算子。

3、資料封裝

        面向物件程式設計是通過為資料和程式碼建立分塊的記憶體區域,以便提供對程式進行模組化的程式設計方法,這些模組可以被用作樣板,在需要時再建立副本。而物件是計算機記憶體中的一塊區域,通過將記憶體分塊,每個物件在功能上保持相對獨立。這些記憶體塊中不但儲存資料,也儲存程式碼,只有物件中的程式碼才可以訪問儲存於這個物件中的資料,這將保護它自己不受未知外部事件的影響,從而使自己的資料和功能不會遭到破壞。

        在面向物件的程式中,只有向物件傳送訊息才能引用物件的行為,所以面向物件是訊息處理機制,物件之間只能通過成員函式相互呼叫來實現相互通訊。這樣,物件之間相互作用的方式是受控制的,一個物件外部的程式碼就沒有機會通過直接修改物件的記憶體區域妨礙物件發揮其功能。

        面向物件就是將世界看成是一組彼此相關並能相互通訊的實體即物件組成的,程式中的物件對映現實世界中的物件。

        C++對其物件的資料成員和成員函式的訪問是通過訪問控制權限來限制的,一般情況下將資料成員說明為私有的,以便隱藏資料,將部分成員函式說明為公有的,用於提供外界和這個類的物件相互作用的介面,從而使得其他函式也可以訪問和處理該類的物件。

二、建構函式

1、預設建構函式

        沒有定義建構函式,卻可以使用類直接產生物件,原因是當沒有為一個類定義任何建構函式的情況下,C++編譯器總要自動建立一個不帶引數的建構函式。預設的建構函式函式名與類名相同,函式體是空的,沒有引數,也沒有返回值,如果它有返回值,編譯器就必須知道如何處理返回值,這樣會大大增加編譯器的工作,降低了效率。如果我們在程式中定義了自己的建構函式,系統就不再提供預設的建構函式。如果我們需要使用到無參的建構函式,則需要在顯式的宣告並定義一個無參的建構函式。

2、定義建構函式

#include <iostream>
using namespace std;

class Point{
private:
	int x,y;
public:
	Point();//宣告一個無參的建構函式
	Point(int,int);//宣告一個有兩個引數的建構函式
};

Point :: Point(){//定義無參的建構函式
	cout << "預設初始化物件" << endl;
}
Point :: Point(int a,int b):x(a),y(b){//定義兩個引數的建構函式,x(a)相當於x = a,它跟下面的宣告方式是等價的
	cout << "初始化物件,屬性x:" << a << ",屬性y:" << b <<endl;
}
/*Point :: Point(int a,int b){
	x = a;
	y = b;
}*/

int main(){
	Point a;//使用無參建構函式產生物件
	Point b(10,20);//使用有參建構函式產生物件
	Point c[2];//使用無參建構函式產生物件陣列
	Point d[2]={Point(15,25),Point(20,30)};//使用有參建構函式產生物件陣列
	/**
	 * 初始化物件,屬性x:10,屬性y:20
	 * 預設初始化物件
	 * 預設初始化物件
	 * 初始化物件,屬性x:15,屬性y:25
	 * 初始化物件,屬性x:15,屬性y:25
	 */
}

3、建構函式和運算子new

        運算子new用於建立生存期可控的物件,new返回這個物件的指標。當使用new建立一個動態的物件時,new將首先分配保證類的一個物件所需要的記憶體,然後自動呼叫建構函式來初始化這塊記憶體,再返回這個動態物件的地址。

        使用new建立的動態物件只能使用delete刪除,以便釋放所佔空間。

    Point *p1 = new Point();
	Point *p2 = new Point(5,8);
	delete p1;
	delete p2;
	/**
	 * 預設初始化物件
	 * 初始化物件,屬性x:5,屬性y:8
	 */

4、建構函式的預設引數

class Point1{
private:
	int x,y;
public:
	Point1(int=0,int=0);//宣告一個預設引數的建構函式,使用預設引數的建構函式就不能再宣告無參的建構函式
};
Point1 :: Point1(int a,int b):x(a),y(b){//定義兩個引數的建構函式
	cout << "初始化物件,屬性x:" << a << ",屬性y:" << b <<endl;
}

int main(){
	Point1 a;
	Point1 b(10,25);
}

5、複製建構函式

        引用在類中可以用在複製建構函式中,編譯器建立一個預設複製建構函式,然後採用拷貝式的方法使用已有的物件來建立新物件。複製建構函式必須使用物件的引用為形式引數,為了安全起見,建議使用const限定符。

class Point2{
private:
	int x,y;
public:
	Point2();
	Point2(const Point2&);//宣告帶const限定符的複製建構函式
};
Point2 :: Point2():x(12),y(20){
	cout << "初始化物件,屬性x:" << x << ",屬性y:" << y <<endl;
}
Point2 :: Point2(const Point2 &p){
	x = p.x;//一個類中定義的成員函式可以訪問該類任何物件的私有成員
	y = p.y;
	cout << "初始化物件,屬性x:" << x << ",屬性y:" << y <<endl;
};

int main(){
	Point2 a;
	Point2 b(a);
	/**
	 * 初始化物件,屬性x:12,屬性y:20
	 * 初始化物件,屬性x:12,屬性y:20
	 */
}

三、解構函式

        在物件消失時,應使用解構函式釋放由建構函式分配的記憶體。建構函式、複製建構函式和解構函式是構造型成員函式的基本成員。

1、定義解構函式

        解構函式的函式名稱與類名一樣,為了與建構函式進行區分,在解構函式的前面加一個“~”號。在定義解構函式時,不能指定任何返回型別,也不能指定任何引數,但是可以顯式的宣告引數為void,即A::~A(void),一個類只能定義一個解構函式。

void example3();
class Point3{
private:
	int x,y;
public:
	Point3(int,int);//宣告兩個引數的建構函式
	~Point3();//宣告解構函式
};

Point3 :: Point3(int a,int b):x(a),y(b){//定義兩個引數的建構函式
	cout << "Initializing" << endl;
}
Point3 :: ~Point3(){
	cout << "Destructor is active" << endl;
}

int main(){
	example3();
	return 0;
}

void example3(){
	Point3 a(10,20);//通過建構函式例項化一個物件
	cout << "Exiting main function" << endl;

/**
 * Initializing //建立物件時呼叫建構函式
 * Exiting main function //在程式結束之前呼叫解構函式
 * Destructor is active //程式自動呼叫建構函式
 */
}

         當物件的生命週期結束時,程式為這個物件自動呼叫解構函式,然後回收這個物件佔用的記憶體。全域性物件和靜態物件的解構函式在程式執行結束之前呼叫。類的物件陣列的每個元素呼叫一次解構函式。全域性物件的解構函式在程式結束之前被呼叫。

        如果在定義類時沒有定義解構函式,C++編譯器也要為它產生一個函式體為空的預設解構函式。

2、解構函式和運算子delete

        運算子delete與解構函式一起工作,當使用運算子delete刪除一個動態物件時,它首先為這個動態物件呼叫解構函式,然後再釋放這個動態物件佔用的記憶體,這與使用new建立動態物件的過程剛好相反。

void example4();
class Point3{
private:
	int x,y;
public:
	Point3(int=0,int=0);//宣告兩個引數的建構函式
	~Point3();//宣告解構函式
};

Point3 :: Point3(int a,int b):x(a),y(b){//定義兩個引數的建構函式
	cout << "Initializing" << a << "," << b << endl;
}
Point3 :: ~Point3(){
	cout << "Destructor is active" << endl;
}

int main(){
	example4();
	return 0;
}

void example4(){
	Point3 *p = new Point3[2];//建立物件陣列
	delete [] p;//動態刪除物件
/**
 * Initializing0,0
 * Initializing0,0
 * Destructor is active
 * Destructor is active
 */
}

        當使用delete釋放動態物件陣列時,必須告訴它這個動態物件陣列有幾個元素物件,C++使用“[]”來實現 。然後,delete將為動態陣列的每個物件呼叫一次解構函式,並釋放記憶體。

        當程式先後建立幾個物件時,系統將按照先建立後析構的原則進行析構物件,當使用delete呼叫解構函式時,則按delete的順序析構。

四、呼叫複製建構函式的綜合例項

void example5();
void example6();
void example7();
void example8();
class Point4{
private:
	int x,y;
public:
	Point4(int=0,int=0);//預設引數建構函式
	Point4(const Point4&);//複製建構函式
	~Point4();//解構函式
	void show(){
		cout << "x=" << x << ",y=" << y << endl;
	}
};

Point4 :: Point4(int a,int b):x(a),y(b){//定義預設建構函式
	cout << "使用預設引數建構函式初始化物件!x=" << x << ",y=" << y << endl;
}
Point4 :: Point4(const Point4 &p){//定義複製建構函式
	x = p.x;
	y = p.y;
	cout << "使用複製建構函式初始化物件!x=" << x << ",y=" << y << endl;
}
Point4 :: ~Point4(){//定義解構函式
	cout << "析構物件,x=" << x << ",y=" << y << endl;
}

void show1(Point4 p){//使用物件作為引數的方法
	cout << "使用物件作為引數,";
	p.show();
}
void show2(Point4 &p){//使用物件引用作為引數的方法
	cout << "使用物件引用作為引數,";
	p.show();
}
Point4 getPoint4(){//返回值為物件的方法
	Point4 p(10,20);
	return p;
}

int main(){
	example8();
	return 0;
}

//測試返回物件時的函式呼叫流程
void example8(){
	Point4 a = getPoint4();
	show2(a);
	/**
	 * 使用預設引數建構函式初始化物件!x=10,y=20
	 * 使用物件引用作為引數,x=10,y=20
	 * 析構物件,x=10,y=20
	 */
}

//測試函式的形參為物件引用時函式呼叫流程
void example7(){
	Point4 a(17,27);
	show2(a);
	/**
	 * 使用預設引數建構函式初始化物件!x=17,y=27
	 * 使用物件引用作為引數,x=17,y=27
	 * 析構物件,x=17,y=27
	 */
}

//測試函式的形參為物件時的函式呼叫流程
void example6(){
	Point4 a(16,26);
	show1(a);
	/**
	 * 使用預設引數建構函式初始化物件!x=16,y=26
	 * 使用複製建構函式初始化物件!x=16,y=26 //建立臨時物件
	 * 使用物件作為引數,x=16,y=26
	 * 析構物件,x=16,y=26 //先析構臨時物件
	 * 析構物件,x=16,y=26
	 */
}

//測試用一個類的物件去初始化另一個物件
void example5(){
	Point4 a(15,25);//呼叫建構函式初始化物件a
	Point4 b(a);//使用物件a初始化物件b
	/**
	 * 使用預設引數建構函式初始化物件!x=15,y=25
	 * 使用複製建構函式初始化物件!x=15,y=25
	 * 析構物件,x=15,y=25
	 * 析構物件,x=15,y=25
	 */
}

         從上面的程式執行情況來看,當函式的形參是類的物件時,呼叫函式時需要呼叫複製建構函式。而傳物件就是傳值的方式,所以需要構造一個臨時物件,在退出時再析構該物件。相比較而言,傳引用是傳地址的方式,所以不需要構造臨時物件,所以傳物件的引用比傳物件要好。

六、this指標

        在定義Point類的物件a之後,當執行語句“a.getX()”時,計算是怎麼知道獲取哪個物件的值呢?其實成員函式getX()有一個隱藏引數,名為this指標,當源程式被編譯後,getX()的實際形式如下:

int Point :: getX((Point*)this){
    return this -> x;
}

        C++規定,當一個成員函式被呼叫時,系統自動向它傳遞一個隱藏的引數,該引數是一個指向呼叫該函式的物件的指標,從而使用成員函式知道該對哪個物件進行操作。在程式中可以使用this關鍵字來引用該指標。 

七、一個類的物件作為另一個類的成員

void example9();
class Desk{
private:
	int num;//數量
public:
	void setNum(int a){
		num = a;
	}
	int getNum(){
		return num;
	}
};
class Bed{
private:
	int num;//數量
public:
	void setNum(int a){
		num = a;
	}
	int getNum(){
		return num;
	}
};
class House{
private:
	Desk d;
	Bed b;
public:
	void setHouse(Desk &d,Bed &b){
		this -> d = d;
		this -> b = b;
	}
	int getTotal(){
		return d.getNum() + b.getNum();
	}
};

int main(){
	example9();
	return 0;
}

void example9(){
	Bed b;
	b.setNum(2);
	Desk d;
	d.setNum(5);
	House h;
	h.setHouse(d,b);
	cout << "屋子裡一共有" << h.getTotal() << "件傢俱!";
	/**
	 * 屋子裡一共有7件傢俱!
	 */
}

八、類和物件的性質

1、物件的性質

① 同一類的物件之間可以相互賦值,如:

Point a,b; 
a.setXY(10,20);
b = a;

② 可以使用物件陣列,如:

Point a[2];

 ③ 可以使用物件的指標,如:

Point a(10,20);
Point *p = &a;
p -> display();//使用物件指標呼叫成員函式

④ 物件可以用作函式引數。如果傳物件值,呼叫函式時對形參的改變不會影響呼叫函式中實參的物件;如果傳的是物件的引用(地址),當引數物件被改變時,相應的實參物件也會被修改;如果傳的是物件的地址值,可以使用物件指標作為引數,可以達到傳引用相同的效果。為了避免被呼叫函式修改原來物件的資料成員,可以使用const修飾符。

⑤ 物件作為函式引數時,可以使用物件、物件引用和物件指標;

⑥ 一個物件可以用作另一個物件的成員。 

2、類的性質

⑴ 使用類的許可權

① 類本身的成員函式可以使用類的所有成員(包括公有和私有);

② 類的物件只能訪問公有成員函式;

③ 其他函式不能使用類的私有成員,也不能使用公有成員函式,它們只能通過類的物件使用類的公有成員函式;

④ 雖然一個類可以包含另外一個類的物件,但這個類只能通過被包含類的物件使用那個類的成員函式,再通過成員函式使用資料成員。

⑵ 不完全的類宣告

        類不是記憶體中的物理實體,只有當一個類產生物件時,才會分配記憶體,這種物件建立的過程被稱為例項化。類必須在其使用之間先進行宣告,有時也需要將類作為一個整體來使用,而不存取成員。如下:

class Point;//不完全類宣告
Point *p;//全域性的類指標
void main(){}//主函式
class Point{//類體};//完全定義類

        不完全類宣告,用於在類沒有完全定義之前就引用該類的情況,比如:引用另一檔案中定義的類,由於類識別符號Point通過類宣告進入作用域,所以就可以宣告全域性變數指標p,當編譯器執行到該指標宣告處,只瞭解指標所指型別是一個叫Point的類,而不瞭解其他情況。

        不完全類宣告的類不能例項化,也不能存取沒有完全宣告的類成員,否則會編譯錯誤。 

⑶ 空類

        儘管類的目的是封裝程式碼和資料,但它也可以不包括任何宣告。如:

class Point{};

         這種類沒有任何行為,但可以產生空類物件。

⑷ 類的使用域

        宣告類時所使用的一對花括號形成所謂的類作用域,在類作用域中宣告的識別符號只在類中可見。

九、面向物件的標記圖

1、類和物件的UML標記圖

類圖如下:

2、物件的結構和連線

        只有定義和描述了物件之間的關係,各個物件才能構成一個整體的、有機的系統模型,這就是物件的結構與連線關係。物件結構是指物件之間的分類(繼承)關係和組成(聚合)關係,統稱為關聯關係。物件之間的靜態關係是通過物件屬性之間的連線反映的,稱之為例項連線。物件行為之間的動態關係是通過物件行為(訊息)之間的依賴關係表現的,稱之為訊息連線,例項連線和訊息連線統稱為連線。

⑴ 分類關係及其表示

        C++中的分類結構是繼承結構。UML使用一個空三角形表示繼承關係,三角形指向基類。如下:

⑵ 物件組成關係及其表示

        組成關係說明的結構是整體與部分的關係。C++中的聚合隱含了兩種實現方式,第一種是獨立的定義,可以屬於多個整體物件,並具有不同的生存期,它用空心菱形表示。第二種方式是用一個類的物件作為一種廣義的資料型別來定義整體物件的一個屬性,構成一個巢狀物件,它用實心菱形來表示。如下:

⑶ 例項連線及其表示

        例項連線反映物件之間的靜態關係。簡單的例項連線是物件例項之間的一種二元關係,例項連線用一條實線表示。比如:老師指導學生論文。

⑷ 訊息連線及其表示

        訊息連線描述物件之間的動態關係。即一個物件在執行自己的操作時,需要通過訊息請求另一個物件為它完成某種服務,也就是說兩個物件之間存在著訊息連線。訊息連線是有方向的,使用一個帶箭頭的實線表示,從訊息的傳送者指向訊息的接收者。

3、物件、類和訊息

        物件的屬性是指描述物件的資料成員,物件的屬性集合又稱為物件的狀態。物件的行為是定義在物件屬性上的一組操作的集合,操作是響應訊息而完成的演算法,表示物件的內部實現細節,物件的操作集合體現了物件的行為能力。

        物件一般具有以下特徵:

① 有一個狀態,由與其關聯的屬性值集合所表示;

② 有唯一標識名,可以區別其他物件;

③ 有一組操作方法,每個操作決定物件的一種行為;

④ 物件的狀態只能被自己的行為所改變;

⑤ 物件的操作包括自身操作和施加於其他物件的操作;

⑥ 物件之間以訊息傳遞的方式進行通訊;

⑦ 一個物件的成員仍可以是一個物件。

        訊息是向物件發出的服務請求,它是面向物件系統中實現物件之間的通訊和請求任務的操作。一個物件所能接受訊息及其所帶的引數,構成該物件的外部介面。物件接收它能識別的訊息,並按照自己的方式來解釋和執行。一個物件可以同時向多個物件傳送訊息,也可以接收多個物件發來的訊息。物件傳遞的訊息一般由三個部分組成:接收物件名、呼叫操作名和必要的引數。向物件傳送一個訊息,就是引用一個方法的過程。

        訊息協議是一個物件對外提供服務的規定格式說明,外界物件能夠向該物件傳送協議中所提供的訊息,請求該物件服務。訊息分為公有和私有訊息,私有訊息只供類的內部使用的訊息,公有訊息是對外的介面,協議則是一個物件所能接受的所有公有訊息的集合。

十、面向物件程式設計的檔案規範

        在程式設計一般要求將類的宣告放在標頭檔案中,非常簡單的成員函式可以在宣告中定義(預設是行內函數),實現放在.cpp檔案中,然後在.cpp檔案中將標頭檔案包含進去。主程式可單獨使用一個檔案,這是多檔案程式設計規範。

        對於規模較大的類,一般會為每個類設立一個頭檔案和實現檔案。但函式模板和類模樣比較特殊,如果使用標頭檔案說明,則同時完成它們的定義,為了避免重複包含標頭檔案,可使用條件編譯的方法。

1、編譯指令

        C++的源程式可包含各種編譯指令,以指示編譯器對原始碼進行編譯之前先對其進行預處理。所有的編譯指令都以#開始,每條指令單獨佔用一行,同一行不能有其他編譯指令和C++語句(註釋除外)。

⑴ 嵌入指令

        嵌入指令#include指示編譯器將一個原始檔嵌入到帶有#include指令的原始檔中該指令所在的位置處。尖括號或雙引號中的檔名可含有路徑資訊。例:#include <iostream> #include "e:\app\myfile.h"

⑵ 巨集定義

        #define定義一個識別符號及串,在源程式中每次遇到該識別符號時,編譯器均用定義的串代替之。該識別符號稱為巨集名,而將替換過程稱之為巨集替換。巨集定義由新行結束,而不是以分號結束,如果要寫多行的巨集定義,則除最後一行外,每行末尾要加上一個“\”,表示巨集定義繼續到下一行。例:

#define MAX(a,b)(a>b)?\
a:b

        如果不再使用定義的巨集,可以使用#undef刪除。 

⑶ 條件編譯指令

        條件編譯指令是#if、#else、#elif、#endif,它們構成類似於C++的if選擇結構,其中#endif表示一條指令結束。編譯指令#error用於輸出出錯資訊,使用形式如下:

#error 出錯資訊

⑷ defined操作符

        關鍵字defined不是指令,而是一個預處理操作符,用於判定一個識別符號是否已經被#define定義過。如下:

defined (MAX)//結果為布林值

2、在標頭檔案中使用條件編譯

        在多檔案設計中,由於檔案包含指令可以巢狀使用,可能會出現不同包含同一個標頭檔案的情況,這就會引起變數及類的重複定義,為了避免這種情況,可對這個類標頭檔案使用條件編譯。如下:

//Point.h
#if !defined(POINT_H)
    #define POINT_H
class Point{
};
#endif