1. 程式人生 > >java與c++區別

java與c++區別

1、指標

C++ 有指標和引用,C++基礎中指標型別和引用型別同等地位重要。C#和java去掉了C++中的難點:指標(可以通過某些方法變相獲得:高階程式設計)保留了引用

C++ 的this關鍵字是一個指標,指向當前物件,所以你會看到用this指標操作類成員使用的是 this->m_member; 引用相當於物件或者基礎型別的別名,利用引用操作成員還是 refClass.m_member java中的this是作為引用來使用的。

2、C++定義類和物件的兩種方式–對比Java

即c++:Test *t=new Test();//若沒()則認為有預設建構函式且呼叫

而java:Test t=new Test();

比如說這裡有一個類:

//C++方式定義一個class
class Son :public Dad 
{
private:
    const int count;
public:
    Son()
    {
        cout<<"Son's constructor"<<endl;
    }
    void sayName()
    {
        cout<<"I am Son"<<endl;
    }
    ~Son()
    {
        cout<<"Son's destructor"<<endl;
    }
};

//java方式定義一個class
class Son extends Dad
{
    private final int count;

    public Son(){}
    public void sayName(){}
}

可以發現,在對class的定義上,C++和Java就有很多差別。這裡舉例幾個:

  1. class宣告最後,C++需要在大括號後面新增分號”;”,而java不用

  2. 繼承的表達,C++使用 冒號+繼承方式 “:public”,Java使用“extends”

  3. 方法和屬性的訪問控制關鍵字,C++是一次性使用,比如上面使用”public:”然後在後面跟所有宣告為public的方法或屬性;而Java則需要在每一個方法或屬性前面都新增訪問控制關鍵字

  4. 建構函式C++和Java都可以有,但是隻有C++可以建立解構函式,Java有垃圾回收機制,所以並不需要解構函式,這是Java對C++的改進之一

  5. Java使用final代替了C++裡面的const,當然static(靜態)的用法還是大家一致的

應該還有別的差別,這裡暫時就列這麼幾點了。

然後再來看物件的宣告方式上,C++和Java的差別。  我們首先先來看C++的,物件的宣告有兩種方式:

1. Son obj; //變數式宣告  

2. Son *obj; //指標式宣告

結合例項程式碼來看這兩種宣告方式會帶來什麼差異:

#include <iostream>
using namespace std;

class Son
{
public:
    Son()
    {
        cout<<"Son's constructor"<<endl;
    }
    void sayName()
    {
        cout<<"I am Son"<<endl;
    }
    ~Son()
    {
        cout<<"Son's destructor"<<endl;
    }
};
int main()
{
    cout<<"Way 1--Son obj1:"<<endl;
    Son obj1;
    obj1.sayName();

    return 0;
}

輸出結果:

Way 1--Son obj1:
Son's constructor
I am Son
Son's destructor

--------------------------------
Process exited after 0.02231 seconds with return value 0
請按任意鍵繼續. . .

這是C++的宣告物件的方式,如果是習慣了很久的Java而把C++忘得差不多了的話,看到這裡的輸出會覺得略驚詫。   沒錯!在Java中”Son obj1;”這樣的物件宣告方式並不會給物件分配空間,僅僅是聲明瞭一個物件的引用,分配的空間只是這個引用的空間,實際的類物件的空間並沒有被建立(初始化)。   然而在C++中,會發現這裡該種建立物件的方式一樣會呼叫建構函式和解構函式!也就是說,C++是支援這種方式宣告物件併為其分配空間的。    所以在物件這塊,我感覺Java對於空間分配相比C++更加嚴格,並且我們知道在java中如果你並沒有給物件分配空間(例如只是上面這樣聲明瞭一個物件:”Son Obj;”但並沒有使用new等方式分配記憶體),那麼你想直接去調該物件的成員方法,是會發現編譯直接就報錯,或者即便編譯通過了(例如Java智慧卡applet平臺的程式設計編譯器就沒提示錯誤),然而執行的時候會發現奇怪的執行結果,然後debug的時候艱難地發現對該物件成員方法的呼叫根本就跳不進去!因為前面沒有用new等方法給物件分配記憶體空間,沒有分配記憶體,何談函式呼叫?

//Java建立未初始化的物件
public class Son {

public Son(){}

public void sayName()
{
    System.out.println("I am Son");
}

public static void main(String[] args) {
    Son obj;
    obj.sayName();
}
}

編譯器會直接提示如下錯誤(物件/變數未初始化就呼叫其成員方法報錯):

The local variable obj may not have been initialized

        所以說我覺得Java對記憶體空間管理比C++嚴格。程式分配記憶體Java就有嚴格的管理,例如要求你要用new關鍵字,然後記憶體的回收Java的垃圾回收機制它又幫你做了,所以在java裡面在記憶體管理這塊就沒C++那麼費心也沒那麼容易出錯,因為它從語言的設計上就對程式設計師遮蔽了容易出錯或者說容易導致不規範程式設計的那幾塊東西。而在C++,你需要考慮和惦記著的東西就多了很多,一旦程式設計不慎,就容易導致錯誤。          上面是C++的第一種建立物件的方式,下面介紹第二種也就是使用指標的方式。當然Java裡面已經對程式設計師遮蔽了指標,所以不存在指標方式建立物件。

​
cout<<"Way 2--Son *obj2:"<<endl;
Son *obj2 = new Son();//若不加()則被認為有為預設建構函式,且呼叫它
obj2->sayName();
delete obj2;

​

程式輸出結果:

Way 2--Son *obj2:
Son's constructor
I am Son
Son's destructor

--------------------------------
Process exited after 0.01643 seconds with return value 0
請按任意鍵繼續. . .

特別注意,這種用new的方式建立物件時,需要用指標來接收new的返回值,而不能是:

Son obj2 = new Son(); 
//編譯器會報錯說[Error] conversion from 'Son*' to non-scalar type 'Son' requested

另外一個需要特別注意的是,這種建立物件的方式之後,對成員方法的呼叫只能使用箭頭:obj->sayName();而不能是obj.sayName();否則編譯報錯提示叫你替換成  ->  。而上面第一種建立物件的方法後面則只能用obj.sayName();呼叫方法,用箭頭則會報錯。

        接下來,就著這第二種建立物件的方式,我們對程式碼做一些調整,看看效果如何:

cout<<"Way 2--Son *obj2:"<<endl;
Son *obj2;
obj2->sayName();
delete obj2;

你猜這樣的程式效果會怎樣?  答案是編譯通過並且執行正常,輸出結果為:

Way 2--Son *obj2:
I am Son
Son's destructor

--------------------------------
Process exited after 0.01833 seconds with return value 0
請按任意鍵繼續. . .

這裡雖然沒有使用new關鍵字,但是程式依然可以呼叫物件的成員方法,同時也可以用delete呼叫解構函式。然而建構函式並沒有被呼叫到。來看個更明顯的例子:

#include <iostream>
using namespace std;

class Son
{
private:
    int i; 
public:
    Son()
    {
        i = 6;
        cout<<"Son's constructor "<<i<<endl;
    }
    void sayName()
    {
        cout<<"I am Son"<<endl;
    }
    ~Son()
    {
        cout<<"Son's destructor"<<endl;
    }
    void setI(int a) 
    {
        i = a;
    }
    int getI()
    {
        return i;
    }
};
int main()
{
//  cout<<"Way 1--Son obj1:"<<endl;
//    Son obj1;
//    obj1.sayName();
    cout<<"Way 2--Son *obj2:"<<endl;
    Son *obj2;
    int r = obj2->getI();
    cout<<r<<endl;

    obj2->setI(3);
    r = obj2->getI();
    cout<<r<<endl;

    return 0;
}

程式在gcc下編譯通過,執行輸出為:

Way 2--Son *obj2:
1528349827
3

--------------------------------
Process exited after 0.01925 seconds with return value 0
請按任意鍵繼續. . .

這證明程式確實沒有呼叫到Son的建構函式(第一遍cout輸出的i的初值為一個奇葩的數,並且每次執行都是固定的這個數),但是Son *obj;這般定義的物件一樣可以直接呼叫其成員方法。並且執行結果最後並沒有自動呼叫解構函式(沒有解構函式的輸出)。可見該物件的作用域不僅限於main函式,證明它是在堆空間儲存。如果運用上面說的java中物件分配空間的嚴格要求,這裡就會顯得很奇怪了,程式並沒有使用new關鍵字,而是直接宣告一個Son型別的指標,然而它卻可以操作成員屬性、呼叫成員方法。問了公司一個程式設計方面挺有經驗的一個前輩,也說不應該編譯通過,應該是堆疊溢位,因為並沒有給該物件分配空間就去操作它的方法了。但是在Dev-gcc的編譯環境下卻可以正常地編譯通過並正常執行,所以這就很難解釋了,究竟是編譯器的問題,還是其實C++是支援這種宣告和使用方式的,有待自己後面發掘答案。

        總結下本篇講的兩種C++定義物件的兩種方式:  1.

Son obj;
obj.method();
Son *obj = new Son();
obj->method();

3、java中的boolean只能是true、false不能用0/1代替

java中boolean型別不惜桑c++中為巨集定義,所以!的取非符號也只能用於boolean型別,不能用於本int 型