C++與Java語法上的不一樣

最近學習算法和刷題基本都是用C++寫的程序,在這個過程當中,發現C++和Java在語法上有不少相同點,但也有不少不一樣點,而這些不一樣點對於已經掌握Java的程序員來講,理解C++代碼可能會有些吃力甚至困難,在踩過了一個又一個坑後,我決定把這些不一樣記錄下來,可能涵蓋的不是很全,因此本文會持續更新。html

零、目錄

1. new關鍵字
2. C++實例化對象的幾種方式
3. C++初始化表達式
4. C++構造函數後的冒號
5. C++中難以省略的分號;
6. C++中的::
7. C++中的*、&、->
8. C++函數前或者函數後的const
9. delete完成後須要將指針置爲NULL

1、new關鍵字

// C++中:
MyClass* a = new MyClass();
delete a;
// Java中:
MyClass a = new MyClass();
  1. C++中new關鍵字實例化對象以後返回的是一個對象的指針,因此須要定義指針;而Java中定義對象時返回的其實也是一個指針(引用),可是在Java中不須要顯示的定義指針。
    不一樣點
  2. C++中經過new關鍵字實例化的對象在使用完畢後須要使用delete關鍵字手動釋放內存;而Java中因爲垃圾回收機制的存在,咱們無需手動釋放內存。

2、C++實例化對象的兩種方式

// 方式一
MyClass* a = new MyClass();
delete a;
// 方式二
MyClass b(params...); // 該方式將會調用有參數的構造函數
MyClass c; //該方式將會調用無參數的構造函數
  1. 方式一中new關鍵字作了三件事:首先在堆內存上得到內存空間(相似malloc函數),而後調用類的構造函數,最後返回該內存空間的指針;由於是在堆內存的動態分配的內存空間,因此最後須要調用delete函數釋放這一部份內存空間。
  2. 方式二中直接在棧內存上分配了存儲空間,相似於基本類型的定義,因此無需手動釋放內存空間,其會在做用域生命週期結束時自動調用析構函數釋放內存;可是當對象信息量較大時,這種作法會佔用不少內存,影響程序效率。

3、C++初始化表達式

int a(10); // 等效於 int a = 10;

與java不一樣,C++除了使用賦值語句初始化變量以外,還可使用上述初始化表達式對變量進行初始化,其效果相同。java

4、C++構造函數後的冒號

// 初始化表達式
class MyClass {
  public:
    const int a;
    int b;
    MyClass(int aVal, int bVal):a(aVal), b(bVal) {}
};
// 非初始化表達式,沒法經過編譯,編譯時會報如下錯誤:
// 'const int MyClass::a' should be initialized
class MyClass {
  public:
    const int a;
    int b;
    MyClass(int aVal, int bVal) {
       a = aVal;
       b = bVal;
    }
};

這個語法其實就是上述第四點中的初始化表達式,但這裏咱們看到下面這種賦值方式在構造函數裏面會報錯,這又是爲何呢?由於這裏咱們的冒號初始化和賦值語句乾的事情不太同樣:在冒號初始化時,只有冒號後面有相應變量的初始化表達式,就會在爲成員變量分配內存時進行初始化,因此常量a在分配內存時作了初始化操做,以後也沒有被改變值,因此不會報錯;而在使用賦值語句時,構造函數在執行到函數體時已經爲a分配了內存但卻沒有對其進行初始化,所以就會報should be initialized編譯錯誤了。程序員

這種神奇的寫法我第一次見的時候也是驚訝了一波。算法

5、C++中難以省略的分號;

在上面例子中咱們看到了C++類的定義後面也要加分號;咱們知道在Java中類定義的大括號後面都無需加分號。
以後查資料發現:
在C++中,除函數,及預編譯指令外,其它的語句或代碼段結尾都必需要加分號。其中預編譯指令是指,以#開頭的語句。常見的有,#include ,#define, #ifdef, #if, #elif, #else,#endif等。函數

6、C++中的::(做用域符)

C++的做用域符::用法有三,一一介紹以下學習

  1. 全局做用域符
int a = 3;
void test() {
  int a = ::a;
  cout << a << endl;
}

這裏就是將全局變量a的值經過全局做用域符的方式訪問到,而後將其值賦給test函數中的局部變量a。spa

  1. 類做用域符
class MyClass {
  public:
    void sayHello();
};
void MyClass::sayHello() {
  cout << "hello world!" << endl;
}

這裏有點相似Java中定義接口和對接口進行實現;首先在類的定義中定義了一個函數sayHello,可是沒有具體函數體,而後在類的定義外,經過做用域符,在函數sayHello前加了一個MyClass::,至關於告訴編譯器,這個函數就是MyClass類的sayHello方法的具體實現。指針

  1. 命名空間做用域符
std::cout << "hello world!" << endl;

這裏std就是命名空間,這樣的用法至關於using namespace std;code

7、C++中的*、&、->

class MyClass {
  public:
    int a;
    MyClass(int aVal):a(aVal){}
};
int main () {
  MyClass obj(5);
  MyClass* objPointer = new MyClass(3);
  // 常規操做
  cout << obj.a << endl;
  // 取指針操做
  cout << (*objPointer).a << endl;
  // ->操做
  cout << objPointer->a << endl;
  // 取地址操做
  cout << (&obj)->a << endl;
  // new出來的對象別忘了釋放內存哦
  delete objPointer;
  return 0;
}

在C++中:htm

  1. *表示訪問指針a指向的變量;
  2. &表示取得變量的地址;
  3. .表示訪問對象的的成員變量或者函數;(與Java相同)
  4. ->表示訪問指針指向的對象的成員變量或者函數;

    指針內容實在太多,這裏就不贅述了,有興趣的童鞋能夠參考菜鳥教程

8、C++函數名前或者函數名後的const

  1. 函數名前的const
const int getVal() {
  const int a = 3;
  return a;
}
int main() {
  cout << getVal() << endl;
}

就是定義函數的返回類型,規定返回變量類型必須爲const。

  1. 函數名後的const(用於類的成員函數中)
class MyClass {
  public:
    int a;
    MyClass(int aVal):a(aVal){}
    void sayHello() const {
      cout << "a value is: " << a << endl;
    }
    // 編譯報錯:assignment of member 'MyClass::a' in read-only object
    void changeA() const {
      a = 5;
    }
};

函數名後面的const表示是該函數爲常成員函數,該函數不能修改對象內的任何成員變量,只能發生讀操做,不能發生寫操做。這樣能夠對成員變量起到保護做用。

9、delete完成後須要將指針置爲NULL

MyClass* a = new MyClass();
delete a;
// 省略下面這句運行時會出現如下錯誤:
// pointer being freed was not allocated
a = NULL;
delete a;

對一個非空指針delete後,若沒有置爲NULL,若再次delete的話,有可能出現問題。而C++標準規定:delete空指針是合法的,沒有反作用。因此每次delete以後要將指針的值置爲NULL。這是一個不得不養成的好習慣,hah...

相關文章
相關標籤/搜索