跳转至

C++ 與其他常用語言的區別

本文介紹 C++ 與其他常用語言的區別,重點介紹 C 與 C++ 之間重要的或者容易忽略的區別。儘管 C++ 幾乎是 C 的超集,C/C++ 代碼混用一般也沒什麼問題,但是瞭解 C/C++ 間比較重要的區別可以避免碰到一些奇怪的 bug。如果你是以 C 為主力語言的 OIer,那麼本文也能讓你更順利地上手 C++。C++ 相比 C 增加的獨特特性可以閲讀 C++ 進階 部分的教程。此外,本文也簡要介紹了 Python, Java 和 C++ 的區別。

C 與 C++ 的區別

宏與模板

C++ 的模板在設計之初的一個用途就是用來替換宏定義。學會模板編程是從 C 邁向 C++ 的重要一步。模板不同於宏的文字替換,在編譯時會得到更全面的編譯器檢查,便於編寫更健全的代碼。模板特性在 C++11 後支持了可變長度的模板參數表,可以用來替代 C 中的可變長度函數並保證類型安全。

指針與引用

C++ 中你仍然可以使用 C 風格的指針,但是對於變量傳遞而言,更推薦使用 C++ 的 引用 特性來實現類似的功能。由於引用指向的對象不能為空,因此可以避免一些空地址訪問的問題。不過指針由於其靈活性,也仍然有其用武之地。值得一提的是,C 中的 NULL 空指針在 C++11 起有類型安全的替代品 nullptr。引用和指針之間可以通過 *& 運算符 相互轉換。

bool

與 C++ 不同的是,C 語言最初並沒有 布爾類型

C99 標準加入了 _Bool 關鍵字(以及等效的 bool 宏)以及 truefalse 兩個宏。如果需要使用 booltruefalse 這三個宏,需要在程序中引入 stdbool.h 頭文件。而使用 _Bool 則不需要引入任何額外頭文件。

1
2
bool x = true;  // 需要引入 stdbool.h
_Bool x = 1;    // 不需要引入 stdbool.h

C23 起,truefalse 成為 C 語言中的關鍵字,使用它們不需要再引入 stdbool.h 頭文件2

下表展示了 C 語言不同標準下,bool 類型支持的變化情況(作為對照,加入了 C++ 的支持情況):

語言標準 bool true/false _Bool
C89 / / 保留3
C99 起,C23 以前 宏,與 _Bool 等價,需要 stdbool.h 頭文件 宏,true1 等價,false0 等價,需要 stdbool.h 頭文件 關鍵字
C23 起 宏,與 _Bool 等價,需要 stdbool.h 頭文件 關鍵字 關鍵字
C++ 關鍵字 關鍵字 保留3

struct

儘管在 C 和 C++ 中都有 struct 的概念,但是他們對應的東西是不能混用的!C 中的 struct 用來描述一種固定的內存組織結構,而 C++ 中的 struct 就是一種類,它與類唯一的區別就是它的成員和繼承行為默認是 public 的,而一般類的默認成員是 private 的。這一點在寫 C/C++ 混合代碼時尤其致命。

另外,聲明 struct 時 C++ 也不需要像 C 那麼繁瑣,C 版本:

1
2
3
4
typedef struct Node_t {
  struct Node_t *next;
  int key;
} Node;

C++ 版本

1
2
3
4
struct Node {
  Node *next;
  int key;
};

const

const 在 C 中只有限定變量不能修改的功能,而在 C++ 中,由於大量新特性的出現,const 也被賦予的更多用法。C 中的 const 在 C++ 中的繼任者是 constexpr,而 C++ 中的 const 的用法請參見 常值 頁面的説明。

內存分配

C++ 中新增了 newdelete 關鍵字用來在「自由存儲區」上分配空間,這個自由存儲區可以是堆也可以是靜態存儲區,他們是為了配合「類」而出現的。其中 delete[] 還能夠直接釋放動態數組的內存,非常方便。newdelete 關鍵字會調用類型的構造函數和析構函數,相比 C 中的 malloc()realloc()free() 函數,他們對類型有更完善的支持,但是效率不如 C 中的這些函數。

簡而言之,如果你需要動態分配內存的對象是基礎類型或他們的數組,那麼你可以使用 malloc() 進行更高效的內存分配;但如果你新建的對象是非基礎的類型,那麼建議使用 new 以獲得安全性檢查。值得注意的是儘管 newmalloc() 都是返回指針,但是 new 出來的指針 只能delete 回收,而 malloc() 出來的指針也只能用 free() 回收,否則會有內存泄漏的風險。

變量聲明

C99 前,C 的變量聲明必須位於語句塊開頭,C++ 和 C99 後無此限制。

可變長數組

C99 後 C 語言支持 VLA(可變長數組),C++ 始終不支持。

結構體初始化

C99 後 C 語言支持結構體的 指派符初始化(但是在 C11 中為可選特性),C++ 直到 C++20 才支持有順序要求的指派符初始化,且 C 語言支持的亂序、嵌套、與普通初始化器混用、數組的指派符初始化特性 C++ 都不支持1

註釋語法

C++ 風格單行註釋 //,C 於 C99 前不支持。

Python 與 C++ 的區別

Python 是目前機器學習界最常用的語言。相比於 C++,Python 的優勢在於易於學習,易於實踐。Python 有着更加簡單直接的語法,比如在定義變量時,不需要提前聲明變量類型。但是,這樣的簡單也是有代價的。Python 相比於 C++ 犧牲了性能。C++ 幾乎適用於包括嵌入式系統的所有平台,並且有着更快的執行速度,但是 Python 只可以在某些支持高級語言的平台上使用。C++ 更接近底層,所以可以用來進行編寫操作系統。

Java 與 C++ 的區別

Java 與 C++ 都是面向對象的語言,都使用了面向對象的思想(封裝、繼承、多態),由於面向對象有許多非常好的特性(繼承、組合等),因此二者有很好的可重用性。所以相比於 Python,Java 和 C++ 更加類似。

二者最大的區別在於 Java 有 JVM 的機制。JVM 全稱是 Java Virtual Machine,中文意為 Java 虛擬機。Java 語言的一個非常重要的特點就是與平台的無關性。而使用 Java 虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平台上運行,至少需要編譯成不同的目標代碼。而引入 Java 語言虛擬機後,Java 語言在不同平台上運行時不需要重新編譯。Java 語言使用 Java 虛擬機屏蔽了與具體平台相關的信息,使得 Java 語言編譯程序只需生成在 Java 虛擬機上運行的目標代碼(字節碼),就可以在多種平台上不加修改地運行。

因為這個特點,Java 經常被用於需要移植到不同平台程序的開發。但是也由於編譯 Java 程序時需要從字節碼開始,所以 Java 的性能沒有 C++ 好。

參考資料


  1. https://en.cppreference.com/w/cpp/language/aggregate_initialization 

  2. https://en.cppreference.com/w/c/23。 

  3. C 和 C++ 均規定,以一個下劃線跟着一個大寫字母開頭的標識符是被保留的,詳見 https://en.cppreference.com/w/c/language/identifier。