程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 輕輕松松從C一路走到C++系列文章之二

輕輕松松從C一路走到C++系列文章之二

編輯:C++入門知識
二、挑戰#define
  
  #define是C提供的一條很有用的指令,但在C++中,很有可能杜絕宏指令的使用。
  
  1 .const
  
  宏指令答應用戶指定某一標識符的值作為一個常量,如:
  
  #define PI 3. 1415926
  
  它也可以用來定義字符串:
  
  #define HZK16 "HZK16F"
  
  以下使用可以通過:
  
   cout << "PI is“<<PI; cout << "Filename: "<< HZK16;
  
  但宏究竟不是一個合法的對象,雖然它偽裝得很完美。C++為用戶提供了常量修飾符const,可以指定某個對象的值為常量。它阻止用戶對其進行賦值或其它副作用,類似於上例:
  
   const float PI=3.1415926; char*const HZK16="HZK16F"; PI = 3. 14; //error HZK16="HZK16K"; //error: Cannot modify a const object
  
  但對於指針的處理似乎有些復雜,例如以下使用卻又合法:
  
  HZK16[5]=’r’; //ok HZK16 ="HZK16K"
  
  清楚地了解const修飾的范圍很有必要,如下是聲明形式與相應含義:
  
  char*const cpl="I love you!“; //const修飾’*’,cp1是一個指向字符的指針常量
  
  const char*cp2="I hate you!“; //const修飾’char' cp2是一個指向字符常量的指針
  
  const char*const cp3="Get the hell out of here!“; // const分別修飾’char’和’*’,cp3是一個指向字符常量的指針常量
  
  因此,以下使用仍合法:
  
  strcpy(cpl "Oh no...“);
  
  cp2++;
  
  因為cpl只管盯住某一處的地址不放,而阻止其中的內容不被改寫則不是它的責任,cp2則恰恰相反,它不答應你修改其中的內容,卻可以被你指來指去(這個下場可能更慘)。只有使用兩個修飾符(如cp3)才可能是最保險的辦法。
  
  指向const的指針不能被賦給指向非const的指針:
  
  float*p=&PI;
  
  //error: Cannot convert 'const float*’ to 'float*’
  
  *p=3.14;
  
  這條限制保證了常量的正當含義。但注重由顯式轉換所引起的常量間接修改是可能的:
  
   //test08.cpp #include <iostream.h> void main() { char * Spy; const char * const String = "Yahoo!"; Spy = (char*)String; Spy[5] = '?'; cout << String; } Yahoo!
  
  **作者按:以上程序在Visual C++下運行會報內存錯誤。
  
  2.內聯函數(in line function)
  
  宏在某些場合能得到類似於函數的功能,如下是一個常見的例子:
  
  #define ADD (a b) ((a)+(b))
  
  cout<<”1+2=”<
  
  它將實現數據求和功能而輸出:
  
  但我們至少有一打理由拒絕使用它,以下是最明顯的:
  
  ①宏缺少類型安全檢測,如:
  
  ADD ('A' 0. 0l);
  
  這樣的調用將被解釋為合法,而事實上,很少的用戶期望能寫出這樣的語句;
  
  ②宏不會為參數引入臨時拷貝,如:
  
   #define DOUBLE (x)((x)+(x)) int i(1); cout<<DOUBLE(i++); //prints '3'
  
  ③宏不具有地址,例如可能在一個計算器程序中有:
  
  case ' +': Operator = & ADD;
  
  並不能得到合理解釋。
  
  采取函數?然而,使用函數並不是最劃算的支出,它浪費了寶貴的執行時間。使用過匯編語言的讀者可能知道,一般函數執行真正的函數體前後,要做一些現場保護工作,當函數體積很小時,這種冗余的工作量將會遠遠大於函數本身。
  
  為此,C++提供了要害字inline,當用戶希望編譯器將某函數的代碼直接插入到調用點時,可將其設置成inline函數,即在函數定義時加上要害字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);
   }

  
  主函數將被編譯器解釋為:
  
  count<<"1+2=”<<{1+2 };
  
  其行為完全類似於前例的ADD (a b)宏。經驗表明,將使用頻繁而且體積很小的函數聲明為inline是明智的。
  
  3.函數重載(overload)
  
  在實際數據求和操作時,如上節內容中提供的Add()函數是遠遠不夠的,你不得不再添加一些其它代碼,如:
  
   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; }
  
  盡管放心,編譯器會安全地為不同的調用形式找到相應的函數原型。如:
  
   double a b; Add(f 2); //int Add(int int) Add (a b); //double Add (doubledouble)
  
  這樣,不同的函數擁有相同的函數名,即函數重載。函數重載以及後面的模板、虛函數機制形成了“一個接口,多種功能”的特性,即多態性(polymorphism),它是面向對象(OO)的技術之一。
  
  在使用重載機制時,C++提出了許多防止二義性的限制,如:
  
   void fun(int a); int fun(int a); void fun(int& a); void fun (int a int b=0);
  
  很可能引起C ++編譯器的恐慌,它在碰到諸如fun(100)的調用時會十分不滿。用戶有義務保證任一調用形式不產生二義性。以下是一種常見的使用重載機制的例程:
  
   //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()函數分別編碼為Pixel_iii和Pixel_ii,它的形式包含了各入口參數的數據類型。注重,編碼未包含返回值的信息,因而依靠於返回值類型的差異的函數重載是不穩定的。因此,連接器(linker)可以毫不費力地找到相應的模塊。但這對於新舊C版本產生的模塊連接恐
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved