<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-204  評論-149  文章-0  trackbacks-0
     

    從Java到C++ — 對比Java與C++編程的不同

    14th August 2007, 11:40 pm

    原作:Cay Horstmann 英文原文

    翻譯:Aqua  prglab.com

    注:很多程序員包括本人在內(nèi)都是先學會的Java,然后才學的C++,其實C++與Java有很多相似和互通之處,有相當?shù)腏ava知識可以對應轉(zhuǎn)化到C++概念,從而幫助我們快速上手。這篇文章介紹的內(nèi)容就對從Java向C++轉(zhuǎn)變很有幫助,所以翻譯推薦給有同樣需要的朋友。翻譯中加入了本人的理解,不完全是全文照搬。有不明或異議,請參考原文,或留言討論。還是那句話,推薦多讀原版資料。

    學習怎樣從一種編程語言轉(zhuǎn)移到另一種編程語言是今日的程序員必須面對的現(xiàn)實,還好,C++和Java有很多共同的特點,所以從Java轉(zhuǎn)到C++就容易許多。C++比Java復雜很多,本文并沒打算涵蓋所有C++的功能。但是如果你能夠熟練掌握本文中的所有知識點,也足夠有效的使用C++了。

    這里我們只講Java與C++的不同之處。像流程控制(if, while, for)這些在C++與Java中完全一樣的內(nèi)容這里就不講了。

    本文是基于ANSI C++標準的,一些老的C++ 編譯器可能不支持這里講到的一些重要功能。要使用這些編譯器,你需要更多學習C++中從C繼承來的部分。那些都超出了本文的范疇,也就不介紹了。

    1. 數(shù)據(jù)類型和變量

    C++ 中的變量類型與Java很相似。像Java一樣,C++ 有intdouble類型。但是這些數(shù)字類型的取值范圍是依賴于機器的。比如在16位系統(tǒng)上,例如運行DOS 或Windows 3.x的PC機上,int是雙字節(jié)(2-byte)的,取值范圍比Java的4-byte的int要小很多。在這些機器上,如果 int 不夠用的話,你需要使用長整型long。

    C++ 有 shortunsigned類型來更有效的存儲數(shù)字。(我認為所謂有效是指更高的空間利用率。) 最好是盡量避免使用這些類型除非是空間利用的有效性對你的系統(tǒng)真的非常重要。

    在C++中布爾型用 bool表示,而不像在Java中用boolean。

    C++ 中字符串類型用 string表示。它與Java中的 String類型非常相似,但是,還是要逐一以下幾點不同之處:

    1. C++ 字符串存儲ASCII 碼字符,而不是標準碼Unicode 字符

    2. C++ 字符串是可以被修改的,而Java字符串的內(nèi)容是不可修改的(immutable)。

    3. 取子字符串的操作在 C++ 中叫做 substr,這個命令s.substr(i, n)從字符串s中取得從位置 i 開始長度為n的子字符串。

    4. 在C++中,你只能夠?qū)⒆址c其它字符串對象相串聯(lián)(concatenate),而不能夠與任意的對象相串聯(lián)。

    5. C++中可以直接使用關系操作符 ==、 !=、 <、 <=、 >、 >= 來進行字符串比較,其中后面四個操作符是按字母順序進行比較的。這比Java中使用函數(shù)equals和compareTo來比較要方便很多。

    2. 變量和常量

    在C++中,本地變量的定義看起來與Java中相同,例如:

    int n = 5;

    實際上這正是C++和Java的一個重要不同之處。C++編譯器不對本地變量進行初始化檢驗,所以在C++中很容易忘記初始化一個變量,這種情況下,變量的值該變量所占內(nèi)存區(qū)域中剛好當前存在隨機值。這顯然是很容易產(chǎn)生程序出錯的地方。

    與Java一樣, C++中類可以有數(shù)據(jù)域和靜態(tài)變量。不同的是,C++中變量可以在函數(shù)甚至是類的外面定義,這些所謂的全局變量可以在程序的任何函數(shù)中被訪問,因而不易被很好的管理。所C++中應該盡量避免使用全局變量。

    在C++中,常量可以在任何地方被定義(記得在Java中,常量必須是類的靜態(tài)數(shù)據(jù)static data)。 C++ 使用關鍵字 const來定義常量,而Java中是 final。例如:

    const int DAYS_PER_YEAR = 365;

    3. 類

    C++ 中對類的定義與Java有些不同,這里是一個例子:一個C++ 版本的 Point類:

    class Point /* C++ */

    {

    public:

    Point();

    Point(double xval, double yval);

    void move(double dx, double dy);

    double getX() const;

    double getY() const;

    private:

    double x;

    double y;

    };

    這里幾點重要的不同是:

    1. C++的類定義中分為公共和私有部分,分別以關鍵字 publicprivate開始。而在Java中,每一個元素都必須標明 publicprivate

    2. C++中類的定義只包含函數(shù)的聲明,真正的實現(xiàn)另外單獨列出。

    3. 訪問函數(shù)(accessor methods)標有關鍵字 const,表明這個函數(shù)不會改變本對象的元素值。

    4. 類定義的結(jié)尾處有分號

    類中函數(shù)的實現(xiàn)跟在類的定義之后。因為函數(shù)是在類外面定義的,所以每一個函數(shù)的名字前面要加類名稱作為前綴,并使用操作符雙冒號::來分割類的名稱和函數(shù)的名稱。不改變隱含參數(shù)值(即當前對象的值)的訪問函數(shù)用 const標明。如下所示是上面類定義中的函數(shù)的實現(xiàn):

    Point::Point() { x = 0; y = 0; }

    void Point::move(double dx, double dy)

    {

    x = x + dx;

    y = y + dy;

    }

    double Point::getX() const

    {

    return x;

    }

    4. 對象

    Java 與 C++ 最主要的不同在于對象變量的使用。

    在 C++中,對象變量存儲的是真正的對象的值,而不是對象引用(reference)。注意在C++中構(gòu)造一個對象的時候是不使用關鍵字new的,只需要在變量的名字后面直接賦予構(gòu)造函數(shù)的參數(shù)就可以了,例如:

    Point p(1, 2); /* 構(gòu)造對象 p */

    如果不跟參數(shù)賦值,則使用默認構(gòu)造函數(shù),例如:

    Time now; /* 默認使用構(gòu)造函數(shù) Time::Time() */

    這一點與Java很不同。在Java中,這個命令僅僅生成一個沒有初始化的對象reference,要創(chuàng)建對象還得使用new在堆中創(chuàng)建一個實際的對象.  

    而在C++中,它生成一個實際的對象。

    當一個對象被賦給另一個對象變量的時候,實際的值將被拷貝。而在Java中,拷貝一個對象變量只不過是建立了另外一個指向?qū)ο蟮膔eference。拷貝一個C++的對象就像在Java中調(diào)用clone這個函數(shù)一樣,而修改拷貝的值不會改變原對象的值。例如:

    Point q = p; /* 拷貝p到q ,q是另外一個新的對象,有自己的內(nèi)存空間*/

    q.move(1, 1); /* 移動q而p不動,即q的值變了,而p的不變*/

    多數(shù)情況下,C++中這種對象直接對值操作的特性使用起來很方便,但是也有些時候不盡如人意:

    C++中對象的指針非常類似于Java中的引用

    1. 當需要一個函數(shù)中修改一個對象的值,必須記住要使用按引用調(diào)用call by reference (參見下面函數(shù)部分),或者將參數(shù)定義為指針類型,在函數(shù)中通過指針來操作其實際指向的對象

    2. 兩個對象變量不能指向同一個對象實體。如果你要在C++中實現(xiàn)這種效果,必須使用指針pointer(參見下面指針部分)

    3. 一個對象變量只能存儲一種特定的類型的值,如果你想要使用一個變量來存儲不同子類的對象的值(多態(tài)ploymorphism),則需要使用指針。

    4. 如果你想在C++中使用一個變量來或者指向null或者指向一個實際的對象,則需要使用指針

    5. 函數(shù)

    在Java中,每一個函數(shù)必須或者是對象函數(shù)(instance method),或者是靜態(tài)函數(shù)(static function)或稱類函數(shù)。C++同樣支持對象函數(shù)和靜態(tài)函數(shù)(類函數(shù)),但同時C++也允許定義不屬于任何類的函數(shù),這些函數(shù)叫做全局函數(shù)(global functions)

    特別的是,每一個C++ 程序都從一個叫做 main的全局函數(shù)開始執(zhí)行:

    int main()

    { . . .

    }

    還有另外一個格式的main函數(shù)可以用來捕捉命令行參數(shù),類似于Java的main函數(shù),但是它要求關于C格式的數(shù)組和字符串的知識,這里就不介紹了。

    按照習慣,通常如果程序執(zhí)行成功, main函數(shù)返回0,否則返回非零整數(shù)。

    同Java一樣,函數(shù)參數(shù)是通過值傳遞的(passed by value)。在Java中,函數(shù)無論如何都是可以修改對象(類對象)的值的(因為java中傳遞的是java中的引用,相當與C++中的指針。Java函數(shù)返回時也是返回的引用,將此引用拷貝到外面的某個引用變量中)。然而在C++中,因為對象直接存儲的是實際的值而不是指向值的reference,也就是說傳入函數(shù)的是一個實際值的拷貝,因此也就無法修改原來對象的值。(C++中函數(shù)返回時也是要拷貝到外面的變量中的,是指針就拷貝指針,是對象就進行對象的拷貝)

    所以,C++ 有兩種參數(shù)傳遞機制,同Java一樣的按值調(diào)用(call by value) ,以及按地址調(diào)用(call by reference)。當一個參數(shù)是按reference傳遞時,函數(shù)可以修改其原始值。Call by reference 的參數(shù)前面有一個地址號 &跟在參數(shù)類型的后面,例如:

    void raiseSalary(Employee& e, double by)

    { . . .

    }

    下面是一個典型的利用call by reference的函數(shù),在Java中是無法實現(xiàn)這樣的功能的

    void swap(int& a, int& b)

    { int temp = a;

    a = b;

    b = temp;

    }

    如果使用 swap(x, y)來調(diào)用這個函數(shù),則reference參數(shù) ab指向原實際參數(shù)xy的位置,而不是它們的值的拷貝,因此這個函數(shù)可以實現(xiàn)實際交換這兩個參數(shù)的值。

    在 C++中,每當需要實現(xiàn)修改原參數(shù)的值時你就可以使用按地址調(diào)用 call by reference 。

     

     

     

    6. 向量Vector

    C++ 的向量結(jié)構(gòu)結(jié)合了Java中數(shù)組和向量兩者的優(yōu)點。一個C++ 的向量可以方便的被訪問,其容量又可以動態(tài)的增長。如果 T是任意類型,則 vector<T>是一個元素為 T類型的動態(tài)數(shù)組。下面的語句

    vector<int> a;

    產(chǎn)生一個初始為空的向量。而語句

    vector<int> a(100);

    生成一個初始有100個元素的向量。你可以使用push_back函數(shù)來添加元素:

    a.push_back(n);

    調(diào)用 a.pop_back()a中取出最后一個元素(操作后這個元素被從a中刪掉), 使用函數(shù)size可以得到當前a中的元素個數(shù)。

    你還可以通過我們熟悉的 []操作符來訪問向量中元素,例如:

    for (i = 0; i < a.size(); i++) {

    sum = sum + a[i];

    }

    同Java中一樣,數(shù)組索引必須為 0 和a.size() - 1之間的值。但是與Java不同的是,C++中沒有runtime的索引號合法性檢驗。試圖訪問非法的索引位置可能造成非常嚴重的出錯。

    就像所有其它 C++ 對象一樣,向量也是值。如果你將一個向量賦值給另外一個向量變量,所有的元素都會被拷貝過去。

    vector<int> b = a; /* 所有的元素都被拷貝了 */

    對比Java中的情況,在Java中,一個數(shù)組變量是一個指向數(shù)組的reference。拷貝這個變量僅僅產(chǎn)生另外一個指向同一數(shù)組的reference,而不會拷貝每一個元素的值。

    正因如此,如果一個C++函數(shù)要實現(xiàn)修改向量的值,必須使用reference參數(shù):

    void sort(vector<int>& a)

    { . . .

    }

    7. 輸入和輸出

    在C++中,標準的輸入輸出流用對象 cincout表示。我們使用 <<操作符寫輸出,例如:

    cout << “Hello, World!”;

    也可以連著輸出多項內(nèi)容,例如:

    cout << “The answer is ” << x << “"n”;

    我們使用 >>操作符來讀入一個數(shù)字或單詞,例如:

    double x;

    cout << “Please enter x: “;

    cin >> x;

    string fname;

    cout << “Please enter your first name: “;

    cin >> fname;

    函數(shù)getline可以讀入整行的輸入,例如:

    string inputLine;

    getline(cin, inputLine);

    如果到達輸入的結(jié)尾,或者一個數(shù)字無法被正確的讀入,這個流對象會被設置為 failed 狀態(tài),我們可以使用函數(shù) fail來檢驗這個狀態(tài),例如:

    int n;

    cin >> n;

    if (cin.fail()) cout << “Bad input”;

    一旦一個流的狀態(tài)被設為failed,我們是很難重置它的狀態(tài)的,所以如果你的程序需要處理錯誤輸入的情況,應該使用函數(shù) getline然后人工處理得到的輸入數(shù)據(jù)。

    8. 指針pointer

    我們已經(jīng)知道在C++中,對象變量直接存儲的是對象的值。這是與Java不同的,在Java中對象變量存儲的是一個地址,該地址指向?qū)ο笾祵嶋H存儲的地方。有時在C++中也需要實現(xiàn)這樣的布置,這就用到了指針pointer。在 C++中,一個指向?qū)ο蟮淖兞拷凶鲋羔槨H绻鸗是一種數(shù)據(jù)類型,則 T*是指向這種數(shù)據(jù)類型的指針。

    就像 Java中一樣,一個指針變量可以被初始化為空值 NULL,另外一個指針變量的值,或者一個調(diào)用new生成的新對象:

    Employee* p = NULL;

    Employee* q = new Employee(”Hacker, Harry”, 35000);

    Employee* r = q;

    實際上在C++中還有第四種可能,那就是指針可以被初始化為另外一個對象的地址,這需要使用地址操作符 &

    Employee boss(”Morris, Melinda”, 83000);

    Employee* s = &boss;

    這實際上并不是什么好主意。保險的做法還是應該直接讓指針指向使用 new生成的新對象。

    到目前為止,C++ 指針看起來非常像 Java 的對象引用變量。然而,這里有一個很重要的語法的不同。我們必須使用星號操作符 *來訪問指針指向的對象。如果 p是一個指向Employee對象的指針,則 *p才代表了這個對象:

    Employee* p = . . .;

    Employee boss = *p;

    當我們需要執(zhí)行對象的函數(shù)或訪問對象的一個數(shù)據(jù)域時,也需要使用 *p

    (*p).setSalary(91000);

    *p外面的括號是必需的,因為 .操作符比 * 操作符有更高的優(yōu)先級。C的設計者覺得這種寫法很難看,所以他們提供了另外一種替代的寫法,使用 -> 操作符來實現(xiàn) *.操作符的組合功能。表達式

    p->setSalary(91000);

    可以調(diào)用對象*p的函數(shù) setSalary。你可以簡單的記住.操作符是在對象上使用的,-> 操作符是在指針上使用的。

    如果你不初始化一個指針,或者如果一個指針為空值 NULL 或指向的對象不再存在,則在它上面使用 *->操作符就會出錯。 不幸的是 C++ runtime 系統(tǒng)并不檢查這個出錯。如果你范了這個錯誤,你的程序可能會行為古怪或死機。

     

    而在Java中,這些錯誤是不會發(fā)生的。所有的reference都必須初始化,所有的對象只要仍有reference指向它就不會被從內(nèi)存中清除,因此你也不會有一個指向已被刪除的對象的reference。Java的runtime 系統(tǒng)會檢查reference是否為空,并在遇到空指針時拋出一個null pointer的例外(exception)。

    C++ 和 Java還有一個顯著的不同,就是 Java 有垃圾回收功能,能夠自動回收被廢棄的對象。而在C++中,需要程序員自己管理內(nèi)存分配回收。

    C++中當對象變量超出范圍時可以自動被回收。但是使用new生成的對象必須用delete操作符手動刪除,例如:

    Employee* p = new Employee(”Hacker, Harry”, 38000);

    . . .

    delete p; /* 不在需要這個對象 */

    如果你忘記刪除一個對象,那么你的程序有可能最終用光所有內(nèi)存。這就是我們常說的內(nèi)存泄漏 (memory leak)。更重要的是,如果你如果刪除了一個對象,然后又繼續(xù)使用它,你可能覆蓋不屬于你的數(shù)據(jù)。如果你剛巧覆蓋了用于處理內(nèi)存回收的數(shù)據(jù)域,那么內(nèi)存分配機制就可能運轉(zhuǎn)失常而造成更嚴重的錯誤,而且很難診斷和修復。因此,在C++中最好盡量少用指針。

    9. 繼承

    C++和Java中繼承的基本語法是很相似的。在C++中,使用 : public代替Java中的extends來表示繼承關系 。 (C++ 也支持私有繼承的概念,但是不太有用。)

    默認情況下,C++中的函數(shù)不是動態(tài)綁定的。如果你需要某個函數(shù)實現(xiàn)動態(tài)綁定,需要使用virtual聲明它為虛函數(shù),例如:

    class Manager : public Employee

    {

    public:

    Manager(string name, double salary, string dept);

    virtual void print() const;

    private:

    string department;

    };

    同Java一樣,構(gòu)造函數(shù)中調(diào)用父類的構(gòu)造函數(shù)有特殊的語法。 Java使用關鍵字 super。C++中必須在子類的構(gòu)造函數(shù)體外調(diào)用父類的構(gòu)造函數(shù)。下面是一個例子:

    Manager::Manager(string name, double salary, string dept)

    : Employee(name, salary) /* 調(diào)用父類的構(gòu)造函數(shù) */

    { department = dept;

    }

    Java 中在子類函數(shù)中調(diào)用父類的函數(shù)時也使用關鍵字 super。而在C++中是使用父類的名稱加上操作符 ::表示,例如:

    void Manager::print() const

    { Employee::print(); /* 調(diào)用父類的函數(shù) */

    cout << department << “"n”;

    }

    一個 C++ 對象變量只能存儲特定類型的對象值。要想在C++中實現(xiàn)多態(tài)(polymorphism),必須使用指針。一個 T*指針可以指向類型為 TT的任意子類的對象,例如:

    Employee* e = new Manager(”Morris, Melinda”, 83000, “Finance”);

    你可以將父類和不同子類的對象混合收集到一個元素均為指針的向量中,然后調(diào)用動態(tài)綁定的函數(shù),如下所示:

    vector<Employee*> staff;

    . . .

    for (i = 0; i < staff.size(); i++)

    staff[i]->print();

    posted on 2009-05-11 14:58 Frank_Fang 閱讀(497) 評論(0)  編輯  收藏 所屬分類: C++編程
    主站蜘蛛池模板: 免费在线看v网址| 热久久精品免费视频| 特级做a爰片毛片免费看| 香港经典a毛片免费观看看| 中文字幕免费在线看线人动作大片| 狠狠热精品免费观看| 可以免费观看一级毛片黄a| 色婷婷六月亚洲婷婷丁香| 亚洲日韩AV一区二区三区四区| 天天综合亚洲色在线精品| 无码av免费网站| 免费一级毛片在播放视频| 免费国产a理论片| 成人免费看片又大又黄| 亚洲日本一区二区三区在线 | 国产成人99久久亚洲综合精品 | 亚洲乱码日产一区三区| 亚洲夂夂婷婷色拍WW47| 秋霞人成在线观看免费视频| 又粗又硬又黄又爽的免费视频| 色吊丝免费观看网站| 国产成人无码综合亚洲日韩| 亚洲乱色伦图片区小说| 免费观看亚洲人成网站| 亚洲偷偷自拍高清| 最近免费mv在线观看动漫| 免费国产成人高清视频网站| 国产免费AV片在线观看播放| 国产美女做a免费视频软件| 亚洲综合欧美色五月俺也去| 亚洲XX00视频| 亚洲av最新在线观看网址| 999国内精品永久免费观看| 国产亚洲综合一区柠檬导航| 嘿嘿嘿视频免费网站在线观看| 亚洲精品日韩一区二区小说| 亚洲线精品一区二区三区| 免费专区丝袜脚调教视频| 亚洲色图古典武侠| 亚洲免费中文字幕| 日韩大片免费观看视频播放|