從C轉入C++ (轉)

worldblog發表於2007-12-04
從C轉入C++ (轉)[@more@]

C++是C的超集(C的副檔名一般為.CPP),在大都分時候,C可在C++下執行,但有時會有問題,主要有以下幾點:

  • 在C++中可用//表示該符號後面為註釋,如:
    void main() //這是主
  • 在C中以可用以下識別符號,但在C++中它們是關鍵字: asm bed_cast bad_typeid catch class const_cast delete dymanic_cast except finally friend inline namespace new operator private protected public reinterpret_cast static_cast template this throw try type_info typeid using virtual xalloc
  • 在C中,可在前面無宣告和定義時,函式(雖會警告). 但在C++中,任何函式在呼叫前必須宣告或定義.
  • 在C中宣告函式時,可不帶引數,如:
    int FuncA();//實際可能有幾個引數
    而在C++中這僅能中明無引數的函式。
  • 在C中可用舊式的函式定義如:
    int FuncA(x,y)
    int x;
    int y;
    {
    ...
    }
    而在C++中這是不允許的.
  • 在C中可對任何指標賦void指標,下:
    int a;
    int *pint;
    void *pvoid=&a
    pint=pvoid; //C中可以,C++錯
    C++會出錯,因C++無法自動將指標變成另一指標型別,可顯式轉換
    pint=(int*)pvoid;
  • C中enum,srtuct,union可和同範圍內的typedef名一致,而在C++由於可只用名稱引用struct等結構,如:
    struct TypeA
    {
    ...
    };
    則可用 TypeA x;定義結構型變數x。
    固不能與typedef同名,否則編譯器不清楚你到底想要定義什麼。
  • 另sizeof()也有兩個不同點:在C中sizeof('x'),在C中相當於sizeof(int),而在C++中相當於sizeof(char)。另如有列舉
    eumu E(x,y,z);
    sizeof(x)在C中相當於sizeof(int),而在C++中為sizeof(E)。

/文件/c++001.htm#頁首">返回到頁首


  • 區域性變數的宣告
    在C中我們要宣告一個區域性變數,必須在塊的開頭任何語句前宣告,在C++中你可在程式任何一個位置宣告一個變數.因此一般你可在要用某個變數時才宣告它,這樣便於閱讀與維護(你甚至可在for語句中定義)如:
    for(int i=0;i<100;i++) //在C中i必須定義在開始處
    {
    int c=12;
    c*=12;
    int a; //這在C中可是不行的
    ...
    }
  • 範圍分解運算子
    我們都知道:在C中,如在內部(如函式內)宣告一個與外部變數(如全域性)相同的變數時,內部的變數將掩蓋外部變數,(此時外部變數存在但不可見).而在C++中這個外部的變數也是可存取的,只要在該變數前加上"::"即可,如:
    double a;
    ...
    {
    int a; //宣告一與外部浮點變數a相同的整型變數a
    a=3; //這個a為內部變數,整型的
    ::a=3.5; //a為外部,浮點型
    }
  • 內嵌函式(線上函式)
    如在C++中用inline定義一個函式,如:
    inline int FuncA(int a) { ...}
    則統編譯器把對這個函式的呼叫換成實際的函式碼,和宏很類似,但有兩個重要的優勢:1.呼叫函式時,編譯器檢查引數型別,而宏不會.2.如果傳遞給函式,它只會求一次值.而在宏中它求兩次,這有可能帶來問題,如:
    ABS(--i); 若ABS是內嵌函式它和我們想的一樣工作,而如ABS是宏,則i將被減兩次,這可能並不是我們希望的.
    這類函式主要用在進行大的迴圈中,以加度,或在類中使用.它與一般函式的不同的是,如改變了它,則所有呼叫它的源都要重新編譯.
  • 過載函式(我不知為什麼有的書把過載稱為過載,怪彆扭的)
    在C中如你要寫一個求浮點型和整型變數絕對值的函式據,那你必須寫兩個不同的函式(雖然它們內部非常的象)就象下面這樣:
    int AbsI(int i) {...} //整型版的
    double A(double i) {...} //浮點版
    而在呼叫時,不能搞錯,而在C++中你可在同一程式中多次定義同一個函式(但它們不能有完全一樣的形式),則上例可定義成:
    int Abs(int i) {...} //整型版的
    double Abs(double i) {...} //浮點版
    這樣在凋用時可用同一個函式名呼叫,程式會自動呼叫正確的版本,如:
    Abs(3); //整型版
    Abs(-3.5) //調浮點版
    你也可能有時呼叫某函式,而每次用的引數個數不一樣,也可利用該功能完成.
  • 預設函式引數
    C++可在宣告函式時定義預設引數值來減少一些工作,如:
    void ShowText(char *text,int length=-1,int color=0);
    這樣你可用如下的方法呼叫:
    char *t="hello";
    ShowText(t,6,3); //這和平時用法一樣
    ShowText(t,6); //省去一個引數,此時 color=0
    ShowText(t);//省了兩個引數, length=-1;color=0
    呼叫時不能只省去中間的,如
    ShowText(t,,4); //這是錯的
    它在定義時,還要注意:不能在參數列中部定義一個預設變數,而它後面又是正常的變數,(要麼它後面全是預設變數,要麼把它放在最後)如:
    void ShowText(chat *text,int length=-1;int color);//錯
    預設變數一經定義不可在同一範圍內再定義(即使是一樣的)如
    void ShowText(char *text,int length=-1,int color=0);//宣告
    ...
    void ShowText(char *text,int length=-1,int color=0) //定義,這就是錯的
    {...}
    另:在用預設變數和過載函式時要注意它們可能造成執行時出錯(編譯時可能沒問題,如有以下定義:
    void Display(char *buf);
    void Display(char *buf,int length=30);
    這看上去沒有任何問題,但如有以下的呼叫,則出錯;
    Display("hello"); //多義呼叫,程式不知到底應調哪一個
  • 引用型別
    宣告為引用的變數其實是另一變數的別名,可用&定義一引用,如
    int c;
    int &b;
    b=c;
    此時b為c的別名,即c與b有同樣的地址,對b的操作和對c操作是一個效果.它與指標不同,它們是同樣的型別.不能將常量賦值給它:如 b=5;//錯
    也可將函式引數或返回型別宣告為引用,如將引數設為引用,如下
    int FuncA(int &a);
    而有以下呼叫:
    FuncA(b); //則如在函式內改變了a的值,則b的值也發生同樣的改變
    當然此時不能有如下的呼叫(把常量賦給了變數)
    Func(4);
    這除了用於能改變引數的值之外,也常用於引數為結構時(此時不用將整個結構再複製一遍,有利於提高,此時最好也將之定義為常量(見後常量介紹)
    函式的返回值也可定義為引用,此時函式必須返回一個適當的變數,如:
    int a=0;
    int &GetA() {return a}
    void main()
    {
    int N;
    N=GetA(); //N=0,注N並不是a的引用
    GetA()=5; //a=5;相當與a=5
    ++GetA(); //a=6;相當於++a
    }
    由於函式的引用是在函式返回後用的,它不能返回已不存在的變數,特別是返回去自動變數,或是引數的引用,如下例是危險的;
    int &aa()
    {int a;
    return a;}
    int &bb(int b)
    {return b}
    這個程式並不產生編譯錯誤,但它們的結果是無法預料的.這類函式可的返回全域性變數,static,或動態變數(在下面的new/deldet中介紹)
  • new和delete
    C++中一般用new和delete分配和回收塊,使用new時指定資料型別,由分配足以存放指定型別(可為各種型別)的記憶體塊,返回該塊地址作為該指定型別的指標,如:
    int *cc;
    char *ch;
    cc=new int;
    ch=new char[23]; //分配了一個 char型陣列(有23個項)
    它們可由delete回收,如:
    delete cc;
    delete[] ch; //[]表示回收整個陣列,而不是單個元素.
  • 常量
    可用const定義存放常量的變數,如
    const a=100;
    則a是一個常量,它不能在程式中改變,但常量並不象你想象的那麼簡單,它並不象#defind:
    一.常量和指標:
    這也有幾種:
    1.將指標定義為常量,可隨時改變指標的值,但不能改變指標指向變數的值,(相當於只讀指標),如:
    const int *PCI;
    const int a=1;
    int b=2;
    PCI=&a; //OK!
    *PCI=5; //錯,不可改動
    PCI=&b; //OK!
    2.將常量指標定義到非常量變數,此時指標為常量,必須在定義時初始化,此後不能再賦其它地址,但指標指向的變數可變,如:
    int a=1;
    int b=2;
    int *const CPI=&a; //注意這行!
    *CPI=5; //OK
    CPI=&b; //ERROR,不能改變指標!
    3.定義常量指標到常量物件.這時必須在定義指標時初始化,既不能改指標,也不能改指標指向的值.
    4.不能將常量的地址賦於非常量的指標
    二.常量與引用
    可以定義常量物件的引用.它可用常量初始化:
    const int a=1;
    const int &RCA=a;
    也可用變數初始化
    int b;
    const int &RCB=b;
    無論如何都不能用引用改變所指變數的值.
    三.常量和函式
    定義函式的引數或返回型別為常量.
    如將引數中的一般變數定義為常量,沒有什麼意義,如:
    FuncA(const int a); //a本來就不能改變
    我們知道若引數為指標或是引用,則這可改變這此變數的值,但有時,我們可能只對引數的值感興趣(而不想改變它們的值)這時,可用常量定義引數,保證變數的改變不會有什麼副作用,如:
    funcA(const int *P);
    funcB(const int &C); //無論函式如何對P,C操作,原來的值都不會改變.
    另前面講過如函式的引數是引用,則不能用常數為引數呼叫該函式,但如定義為常量引用,則可以, 如:
    void FuncA(const int &r);
    void main()
    {...
    FuncA(5); //還記得前面說的麼,如它只是引用,這是錯的,而現在它沒問題
    ...}
    如函式的返回值是一般變數,則定義返回為常量沒有什麼意義,但如是指標,或是引用,則使函式不能用返回值來改變指向或引用的變數.例:
    const int *funcA()
    { static int p=1; //注意這的static,若為普通變數很危險,見前引用處
    ++p;
    return &p}

    const int &funcB()
    {static int s=100;//同想請注意這個static
    --s;
    return s;}

    void main()
    {int N;
    N=*funcA(); //OK,N為一複製
    N=funcB(); //OK,N也為一複製
    *funcA()=5; //錯,不可改變.
    ++funcB(); //錯,這可參考一下前面"引用"的例子

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987803/,如需轉載,請註明出處,否則將追究法律責任。

相關文章