經(jīng)驗(yàn)分享 從C到C++(二)
C++技術(shù)固然是很時(shí)髦的,許多C用戶都想在盡可能短的時(shí)間內(nèi)為自己貼上C++的標(biāo)簽。介紹C++的書(shū)很多,但只有那些已經(jīng)僥幸入門(mén)的用戶才偶爾去翻翻,仍有不少在C++門(mén)口徘徊的流浪漢。
本文只針對(duì)C用戶,***是一位很不錯(cuò)的老用戶(譬如他在遇到最簡(jiǎn)單的問(wèn)題時(shí)都嘗試著使用指針),通過(guò)一些C和更好的C++(本文用的是Borland C++3.1版本)例程介紹有關(guān)C++的一些知識(shí),讓讀者朋友們“淺入深出”,輕輕松松C to C++!
二、挑戰(zhàn)#define
#define是C提供的一條很有用的指令,但在C++中,很有可能杜絕宏指令的使用。
1 .const宏指令允許用戶指定某一標(biāo)識(shí)符的值作為一個(gè)常量,
如:#define PI 3. 1415926
它也可以用來(lái)定義字符串:#define HZK16 "HZK16F"以下使用可以通過(guò):
- cout << "PI is“<<PI;
- cout << "Filename: "<< HZK16;
但宏畢竟不是一個(gè)合法的對(duì)象,雖然它偽裝得很***。C++為用戶提供了常量修飾符const,可以指定某個(gè)對(duì)象的值為常量。它阻止用戶對(duì)其進(jìn)行賦值或其它副作用,
類(lèi)似于上例:
- const float PI=3.1415926;
- char*const HZK16="HZK16F";
- PI = 3. 14; //error
- HZK16="HZK16K"; //error: Cannot modify a const object
但對(duì)于指針的處理似乎有些復(fù)雜,例如以下使用卻又合法:
- HZK16[5]=’r’; //ok HZK16 ="HZK16K"
清楚地了解const修飾的范圍很有必要,如下是聲明形式與相應(yīng)含義:
- char*const cpl="I love you!“; //const修飾’*’,cp1是一個(gè)指向字符的指針常量
- const char*cp2="I hate you!“; //const修飾’char' cp2是一個(gè)指向字符常量的指針
- const char*const cp3="Get the hell out of here!“; // const分別修飾’char’和’*’,
cp3是一個(gè)指向字符常量的指針常量,因此,以下使用仍合法:
- strcpy(cpl "Oh no...“);
- cp2++;
因?yàn)閏pl只管盯住某一處的地址不放,而阻止其中的內(nèi)容不被改寫(xiě)則不是它的責(zé)任,cp2則恰恰相反,它不允許你修改其中的內(nèi)容,卻可以被你指來(lái)指去(這個(gè)下場(chǎng)可能更慘)。只有使用兩個(gè)修飾符(如cp3)才可能是最保險(xiǎn)的辦法。
指向const的指針不能被賦給指向非const的指針:
- float*p=&PI;
- //error: Cannot convert 'const float*’ to 'float*’
- *p=3.14;
這條限制保證了常量的正當(dāng)含義。但注意由顯式轉(zhuǎn)換所引起的常量間接修改是可能的:
- //test08.cpp
- #include <iostream.h>
- void main()
- {
- char * Spy;
- const char * const String = "Yahoo!";
- Spy = (char*)String;
- Spy[5] = '?';
- cout << String;
- }
- 輸出結(jié)果:Yahoo!
2.內(nèi)聯(lián)函數(shù)(in line function)
宏在某些場(chǎng)合能得到類(lèi)似于函數(shù)的功能,如下是一個(gè)常見(jiàn)的例子:#define ADD (a b) ((a)+(b))
cout<<“1+2=”<它將實(shí)現(xiàn)數(shù)據(jù)求和功能而輸出:但我們至少有一打理由拒絕使用它,以下是最明顯的:
①宏缺少類(lèi)型安全檢測(cè),如:
- ADD ('A' 0. 0l);
這樣的調(diào)用將被解釋為合法,而事實(shí)上,很少的用戶期望能寫(xiě)出這樣的語(yǔ)句;
②宏不會(huì)為參數(shù)引入臨時(shí)拷貝,如:
- #define DOUBLE (x)((x)+(x))
- int i(1);
- cout<<DOUBLE(i++); //prints '3'
③宏不具有地址,例如可能在一個(gè)計(jì)算器程序中有:
- case ' +': Operator = & ADD;
并不能得到合理解釋。
采取函數(shù)?然而,使用函數(shù)并不是最劃算的支出,它浪費(fèi)了寶貴的執(zhí)行時(shí)間。使用過(guò)匯編語(yǔ)言的讀者可能知道,一般函數(shù)執(zhí)行真正的函數(shù)體前后,要做一些現(xiàn)場(chǎng)保護(hù)工作,當(dāng)函數(shù)體積很小時(shí),這種冗余的工作量將會(huì)遠(yuǎn)遠(yuǎn)大于函數(shù)本身。
為此,C++提供了關(guān)鍵字inline,當(dāng)用戶希望編譯器將某函數(shù)的代碼直接插入到調(diào)用點(diǎn)時(shí),可將其設(shè)置成inline函數(shù),即在函數(shù)定義時(shí)加上關(guān)鍵字inline,如:
- //test09.cpp
- #include <iostream.h>
- inline int Add (int a int b)
- {
- return a + b;
- }
- void main O)
- {
- cout<<"1+2=“<<Add(1 2);
- }
主函數(shù)將被編譯器解釋為:
- count<<"1+2=“<<{1+2 };
其行為完全類(lèi)似于前例的ADD (a b)宏。經(jīng)驗(yàn)表明,將使用頻繁而且體積很小的函數(shù)聲明為inline是明智的。
3.函數(shù)重載(overload)
在實(shí)際數(shù)據(jù)求和操作時(shí),如上節(jié)內(nèi)容中提供的Add()函數(shù)是遠(yuǎn)遠(yuǎn)不夠的,你不得不再添加一些其它代碼,如:
- double AddDouble(double a double b)
- {
- return a + b;
- }
- float AddFloat (float a float b )
- {
- return a + b;
- }
特別地,在C++中你可以玩弄名字的技巧,將以上的AddDouble AddFloat皆取名為Add,如:
- double Add(double a double b)
- {
- return a + b;
- }
盡管放心,編譯器會(huì)安全地為不同的調(diào)用形式找到相應(yīng)的函數(shù)原型。如:
- double a b;
- Add(f 2); //int Add(int int)
- Add (a b); //double Add (doubledouble)
這樣,不同的函數(shù)擁有相同的函數(shù)名,即函數(shù)重載。函數(shù)重載以及后面的模板、虛函數(shù)機(jī)制形成了“一個(gè)接口,多種功能”的特性,即多態(tài)性(polymorphism),它是面向?qū)ο螅∣O)的技術(shù)之一。
在使用重載機(jī)制時(shí),C++提出了許多防止二義性的限制,如:
- void fun(int a);
- int fun(int a);
- void fun(int& a);
- void fun (int a int b=0);
很可能引起C ++編譯器的恐慌,它在遇到諸如fun(100)的調(diào)用時(shí)會(huì)十分不滿。用戶有義務(wù)保證任一調(diào)用形式不產(chǎn)生二義性。以下是一種常見(jiàn)的使用重載機(jī)制的例程:
- //test10.cpp
- #include <graphics.h>
- #include <iostream.h>
- void Pixel(int x int y int color)
- {
- putpixel(x y color);
- }
- int Pixel(int x int y)
- {
- return getpixel(x y);
- }
- void main()
- {
- int Driver=VGA Mode=VGAHI;
- initgraph(&Driver &Mode "");
- Pixel(100 100 4);
- int Color = Pixel(100 100);
- closegraph();
- cout << "Color of point(100 100):" << Color;
- }
可以想象C++將以上不同的Pixel()函數(shù)分別編碼為Pixel_iii和Pixel_ii,它的形式包含了各入口參數(shù)的數(shù)據(jù)類(lèi)型。注意,編碼未包含返回值的信息,因而依賴于返回值類(lèi)型的差異的函數(shù)重載是不穩(wěn)定的。因此,連接器(linker)可以毫不費(fèi)力地找到相應(yīng)的模塊。但這對(duì)于新舊C版本產(chǎn)生的模塊連接恐怕添加了麻煩,因?yàn)閭鹘y(tǒng)的C函數(shù)庫(kù)中并沒(méi)有對(duì)函數(shù)名再作手腳的壞習(xí)慣,C++不得不提供關(guān)鍵字extern來(lái)保證這種連接的安全性,如下形式(注意‘C’可要大寫(xiě)):
- extern "C"
- {
- void Pixel(int x int y int Color);
- };
將告訴編譯器只需要在函數(shù)庫(kù)中找相應(yīng)的Pixel模塊,而不必自作聰明。而
- extern "C"
- { //' #include’一定要另起一行
- #include "function. h"
- };
則聲明包含在頭文件function. h中所有函數(shù)模塊皆采取C連接。
希望通過(guò)本文的介紹,能給你帶來(lái)幫助。請(qǐng)繼續(xù)看下一篇>>
【編輯推薦】