C 與 C++ 的真正區別在哪裡?

除了面向對象與面向過程這個回答之外,C與C++的真正區別在哪裡?

這幾年不管是社團實習工作面試都有被問到這個問題。但是「面向對象以及面向過程」這個回答似乎都不是最好或者最完善的答案。

希望能從語言的語言特性,使用場景,設計哲學等方面得到完整解釋。


面向對象以及面向過程等之類的術語懶得說了。


C 語言: 把大象放進冰箱 。

(1) 打開冰箱門 (2)把大象放進去 (3) 關上冰箱門。


c++的版本就會比較多了:


第一種 :(1)打開冰箱門 (2)把大象放進去 (3) 關上冰箱門。


第二種 :首先定義冰箱類 :包含三個方法 (1)開門 (2)關門 (3)放置(參數是大象)然後 定義大象類。接下來,構建大象和冰箱對象,然後調用開門方法 ,放置,最後關門。


第三種 :定義一個容器類 :包含三個方法 (1)打開容器 (2)放入物品 (3)關閉容器 。然後定義物品類。接著定義冰箱類作為容器的繼承者繼承所有功能,定義大象繼承物品所有功能。接下來你就可以像把物品放入容器一樣將大象放進冰箱了。以後你可以用容器類和物品類來解決將猴子放進烤箱,將老虎關進籠子等等。


第四種 :定義模板類,包含三種模板方法 (1)初始化各種準備條件 (2)對於動作的雙方調用某種動作方法 (3)清理現場。然後將第三種方法定義的類和放置方法傳遞給模板就能完成將大象放進冰箱或者將老虎關進籠子的工作了。以後你可以定義各種各樣的類和 方法來完成各種工作,比如將作業交給老師;把金魚餵給貓咪;把煎蛋放進三明治等等


。。。


第N種 :。。。。。。


C++就是為你提供這N種方法的語言。


C++ 幾乎是 C 的超集,只有少量功能 C++ 不支持。

C++ 多出來的東西太多,很難列舉,我截 cppreference 的圖直觀比較一下吧。

C language

C++ language

可以看到,C++ 比 C 多了 classes、templates、exceptions 這些部分,而每個部分也有很多新增的東西。這還只是語言部分,還未談及標準庫。C 有 29 個標準庫頭文件,C++ 有 87 個,除了量,C++ 標準庫的功能要複雜得多。

關於 C/C++的做用時機,引用舊文《C++強大背後 - Milo Yip》的一段落:

使用C++還是C?

C++ 和 C 的設計哲學並不一樣,兩者取捨不同,所以不同的程序員和軟體項目會有不同選擇,難以一概而論。與 C++ 相比,C 具備編譯速度快、容易學習、顯式描述程序細節、較少更新標準(後兩者也可同時視為缺點)等優點。在語言層面上,C++ 包含絕大部分 C 語言的功能(例外之一,C++沒有C99的變長數組VLA),且提供 OOP 和 GP 的特性。但其實用 C 也可實現 OOP 思想,亦可利用宏去實現某程度的 GP,只不過 C++ 的語法能較簡潔、自動地實現OOP/GP。C++ 的 RAII(resource acquisition is initialization,資源獲取就是初始化)特性比較獨特,C/C#/Java 沒有相應功能。回顧歷史,Stroustrup 開發的早期 C++ 編譯器 Cpre/Cfront 是把 C++ 源代碼翻譯為 C,再用 C 編譯器編譯的。由此可知,C++ 編寫的程序,都能用等效的 C 程序代替,但 C++ 在語言層面上提供了 OOP/GP 語法、更嚴格的類型檢查系統、大量額外的語言特性(如異常、RTTI等),並且 C++ 標準庫也較豐富。有時候 C++ 的語法可使程序更簡潔,如運算符重載、隱式轉換。但另一方面,C 語言的 API 通常比 C++ 簡潔,能較容易供其他語言程序調用。因此,一些 C++ 庫會提供 C 的 API 封裝,同時也可供 C 程序調用。相反,有時候也會把 C 的 API 封裝成 C++ 形式,以支持 RAII 和其他 C++ 庫整合等。


C++語言的設計和演化 (豆瓣)

Stroustrup: The C++ Programming Language (4th Edition)

聽 C++ 的創造者給您細細講。

-----------------

Update:

我不贊同面試官問這個是打開話題。

如果是學生,想通過做點玩具項目總結出「C 與 C++ 的真正區別」,還要:

希望能從語言的語言特性使用場景設計哲學等方面得到完整解釋

個人認為有點異想天開。

如果是社招,被問這個問題,那真是浪費時間,直接從項目入手,話題應有盡有。

如果你是個學生,且被問到這種問題,那表明這個面試官估計早早華麗轉身,已經走上光榮的管理崗;另一種可能就是,他一直混學術圈,干點啥事都喜歡上升到「本質」以及「哲學高度」。那麼你該如何應對呢?只做過屁大點項目?剛弄完畢業設計?沒關係,上面給你提到的兩本書好好讀讀,然後就開始扯吧,一定要「見微知著」,一定要「從細節出發」,看到面試官面露微笑,喜不自勝,你就該放心了。

如果你是個工作多年的開發,且被問到這種問題。那你要小心了,你要進入的團隊很可能有點「不務實」,你很有可能在工作中遭遇 如何看待七牛 CEO 許式偉開源的 Cerl? - C++ 這個問題中老許遭遇的尷尬場面。面對剛剛走出校園的熱血青年(各個熟讀 Effective C++ 三部曲,正愁找不到用武之地),你幾乎毫無還手之力,無論你寫了多少年 C++,經歷多少大項目也沒用,做好準備早早退場吧。

--------------------

說實在的:

我見過很多十幾年以上經驗的C/C++工程師,經歷過很多大項目。他們很少提及諸如「C 和 C++的真正區別」 這種話題,他們通常關心 「是否穩定,是否可維護,是否擴展性好」 這種問題。遇到什麼尺寸的腳,你就穿什麼樣的鞋;碰到啥樣的螺絲,你就用對應的扳手。語言的區別在真正工作中,起到的作用實在太有限了。很多老鳥,根本就不區分,統一稱之為 C++,如曾經沸沸揚揚的 0 bug (豆瓣) 一書的作者,就宣稱自己是使用C++的。但區分的很鮮明的,也是有的,如 雲風 和 Linus 那樣的,但人家都是狂噴C++型的,不區分清楚嘴都張不開。我想說,這些老前輩,別看人家不怎麼玩「這標準那標準」,也絕口不提「C與C++的本質區別」,但人家項目都做得很溜,很好使,在線上不間斷運行很多年都很少出問題的。

問這個,還不如問問:

  • 你遇到過 最難調試修復的 bug 是怎樣的?

  • C 語言有哪些缺陷?

或者你就往具體了問:

  • C++ 工程實踐(7):iostream 的用途與局限

  • C++強大背後 - Milo Yip

遠比這種「玄學」問題好得多,另外,我還真沒見過比C++之父更清楚「C與C++ 真正區別」的人。他應該算是這個「領域」的頂級專家了。


一些區別:

C: 編寫C代碼,寫出來的是C代碼。

C++:編寫C++代碼,寫出來的是還是C代碼。

C:運行時內存錯誤。

C++:看起來像是運行時內存錯誤。

C:編譯器警告你。

C++:編譯器警告它自己。

C:1天學會,1年掌握。

C++:1年學會,-1年掌握。

C:Goto有害。

C++:C++可以無害。

C:入門語言。

C++:出門語言。

C:面向過程。

C++:面向C++。

C:一切皆指針。

C++:一切皆編譯器。

C:爛代碼能輕易編過,也能輕易調過。

C++:爛代碼不能輕易編過,也不能輕易調過。

C:說精通的可能精通。

C++:說精通的肯定不精通。


先說一個實際情況,有相當一部分程序員僅僅把c++當成能夠在任意地方聲明變數的c語言來寫程序。即使使用類、繼承之類的特性,也是比較蹩腳的套概念。

好,下面針對題主的問題進行回答:

語言特性前面答主已經列的很詳細了,類、模板這些特性都是現代高級語言的特性,這些特性使得c++可以支持非常複雜的開發模式。

使用場景,個人觀點,所有c可以實現的複雜工程,都可以用c++優雅的實現。甚至包括操作系統內核。c++對於指令、內存的操作的能力是從c繼承過來的,所以要求精確到彙編級的程序可以用c++開發。另外因為c++有面向對象的能力,所以c++可以以腳本語言的形式開發大型複雜工程。

對於設計哲學,c++與c完全是兩門語言。c++是一種提供多種開發範式的面向對象的語言,而c語言僅僅是面向過程的語言。用c++來解決問題,可以優雅的將問題抽象成各種實體部件,相互配合「合力」將問題解決。用c來解決問題,總是將大的過程分解成小的階段或小的過程,把各階段或小的過程結果匯總最後將問題解決。

最後,如果面試官用這個問題來問應屆生,可能意義不大,沒有寫過足夠量代碼的程序員,確實無法將這個問題講清楚。

ps:題主如果一定想體驗一個c++與c的不同,可以去翻翻《c++設計新思維》這本書。


如果面試官問我我就隨便說兩句要是他敢說我錯了我直接糊他一臉然後揚長而去。


我認為,一個是在裸奔,一個是在穿著皇帝的新衣裸奔。。。


很多時候面試官問你這個問題只是想打開一個話題。

如果我是面試官,我期望你通過一個個你經歷的C或者C++項目總結你對這兩個語言的看法,在這個過程中我期望看到你對待項目對待語言對待新知識對待總結新發現的態度和描述能力,我期望聽到:當時某個項目一個什麼坑 和語言的關係是什麼什麼 後來發現了什麼什麼 然後把我晾在一邊,你眼睛放光 激情肆溢。。。。我幾乎不會在乎你說的區別對不對全不全面。

類似think in cpp這類書,他們對這類東西的描述之所以讓你覺得精彩,是你能感受到他們所經歷的一個個項目實踐,而非教科書式遐想總結。。。


請客觀對待刁難你的傻逼面試官。

匿了

[匿]

[匿名]

[anonymous]

[anonymous name]

算了……


我會說我有個朋友一直

#include &
#include &

然後一直用scanf和printf?


c++包含過程編程,面對對象編程和通用編程(模板)

c只有過程編程


抖個機靈。

C沒有對象。

C++有對象。


記得去年自主招生面試,面試的老師就問了我這個問題,「C語言和C++的區別是什麼?」

作為高中生的我當時就懵逼了,於是答道:「一個是面向過程的語言,一個是面向對象的語言」

老師說:「嗯……你說的這是理論層面的,你在實際用的時候有什麼區別么?」

當時我又懵逼了,我特么其實不會C++,我只會C with STL,裝逼裝過了怎麼辦……來了一句:「C++比C多了很多好用的東西啊,比如STL寫起來很方便啊……」,現在深深感受到了當時的認知之短淺(逃……(現在我還是一點也不懂C++


我以前上學的時候也問過同樣的問題,結果那個人回答的是:當然不一樣了,一個面像過程,一個面像對像。然後我又問了一句:那什麼是面像對象,什麼是面像過程。

答曰:這還用問嗎?

從此以後,我明白了一個道理:不懂裝懂的人最丑了。


我現在是本科未畢業生, 和題主一樣有很多不懂的地方, 比如設計哲學和怎麼讓我的輸入法輸入漢文標點. 說一下我的看法, 可能也有很多不對的地方, 也希望有人給我指出來.

---

C++是C的直接後代, 包含了幾乎所有的C語言. C++提供更強的類型檢查, 直接支持了比C更多的編程風格. C++提供了數據抽象, 面向對象編程, 范型編程.

除了"C++包含了幾乎所有的C語言"中的"幾乎所有", 別的方面都比較明顯. 下面解釋一下這個"幾乎所有".

1. 關於類型

double loli = sqrt(2); /* 是C,不是C++ */
int clen = sizeof("a"); /* 1 in C++, sizeof(int) in C */

2. 函數參數

void f(); /* 未指定參數 */
void g()
{
f(2); /* 是C, 不是C++ */
}

3. void*隱式轉換

/* 將void*隱式轉換為int*, 是C, 不是C++ */
int *p = malloc(n * sizeof(char));

4. 保留字

int class = 0; /* 是C, 不是C++ */


C++ 是遵從零簿記原則的多範式語言,包括 C-style part,面向對象,函數式和一個圖靈完全的 template 語言。由於零簿記,所以有很多地方邁不開步子,要用一些妥協的方式。

其面向對象部分野心很大,不是為了純 GUI,而我覺得 GUI 是面向對象發揮的最好的地方。

當然,如果你想知道 C-style part 和 C 部分的區別,可以讀一讀《C++ 設計與演化》,能幫你把那些雜碎的語法知識串聯起來。


大概是......境界的不同吧


設計語言有兩種完全不同的視角。

一種是從硬體角度出發,所有的語言都是為了更方便地操作硬體。從這個角度出發,所有高級語言不過是機器指令的宏。彙編是為了方便人識別機器指令,而C和彙編也是嚴格對應的,除去編譯器優化的可能,對應到某種硬體,讀C代碼,可以腦補為彙編。java也好,python也好,統統都還是要被轉成機器指令的。

比如在寫內核的時候,使用彙編是很繁瑣的事情,這時候使用C可以大大簡化。但是同時腦子裡還是要對內存的使用情況,各種數據結構在內存中的位置,大小,狀態,各種寄存器的值和狀態有很清楚的了解。所以C的使用在這樣的場合更多是為了方便控制硬體,在某些場合還要直接寫彙編,或者通過內聯彙編來控制硬體。比如在bios自檢完畢後,會跳轉到哪個內存位置?這時候處理器處於什麼模式?能夠讀入的內存大小是多少位元組?哪個寄存器可以控制模式轉換?如果我想通過bios函數完成基本的屏幕列印,該怎麼做?系統初始化的時候,我的雙層頁表的目錄儲存在那個虛擬地址位置?對應的物理地址位置又在哪裡?如果硬體不允許我直接操作物理內存,我如何通過操作虛擬地址來分配物理頁面?這些問題,都和硬體有很強的關聯。

另一種則是從解決問題的角度出發。問題可以怎樣被分解,怎樣提高代碼的質量。主要技巧是對基本元素的抽象和組合(根據scip的說法)。從這個角度看來,機器指令是什麼並不重要,編譯器會怎麼翻譯代碼也不太重要。重要在於如何建立良好的程序結構,為了建立這個結構,程序員可能在不同情況下使用多種範式編程。

比如使用oc寫iphone的應用,雖然oc對c的語言特點是完全兼容的,可是我並不關心指令是如何執行的,而是關心我要如何分解問題,有哪些用例,這些用例如何分解為基本的操作,比如資料庫操作,網路操作,這些操作之上是否還有必要加一層?這些不同層次的部件是如何連接在一起的?為了連接他們我需要哪些介面?再比如一個TableView的Cell,是否會有很多類似的cell?我是否有必要抽象這些數據結構?如果這些數據結構在以後被改動,我應該如何處理?如果控制流需要反轉,這時候我是使用委託模式,觀察者模式?或者使用block這樣的closure語法?哪種能使我的程序結構簡化,代碼更少?即使是在優化的時候,大部分的時候我也只是看函數調用的時間,內存佔用的狀態,通過這些信息來了解我該如何調整程序的結構。這時我對內存和CPU的了解是粗糙的。

當然這兩者其實是一個問題兩種看法。用C語言通過類型轉換,也可以實現面向對象,泛型,畢竟不論使用什麼範式,最後還是要翻譯為機器指令。如果你愛好比較奇特,還可以用彙編來面向對象,這也不是不可以。另一方面,要想在python中使用C語言或者彙編更好地控制硬體,也是可以的。問題是,在兩種完全不同的場合下,我是否有必要偏離我的側重點?

C++是兼顧兩種視角的語言,C++希望既能很好地控制硬體,又希望很好地分解問題。至於最後C++到底好不好,我覺得這是個見仁見智的問題。在實際工作中,如果是只用到C++的工作,當然就把C++各種特性以及常用的庫熟悉就好了。

對於我自己而言,我會多學幾門語言。使用的時候,哪個方便就用哪個;不同的框架要求哪個,就使用哪個。用最簡潔的方法解決問題,不正是編程的樂趣所在嗎?


面向對象和面向過程這個答案根本是扯淡嘛。面向對象只是C++的一個特性,C++也可以寫面向過程的代碼啊,還可以寫一部分函數式編程,然後C++的模板元編程是圖靈完備的。一個 new 和malloc 的區別都夠寫一章了。


大四找工作的時候投的百度,人不在北京,一直是電話面試,頭兩次都聊得挺好的,第三次到了約定的點兒了沒人給我打電話,然後我就給HR打過去了,一會兒,有人打過來了,應該是午睡沒醒被叫起來的,然後他就問的第一個問題就是這個:C與C++的區別。


推薦閱讀:

如何評價 Visual C++ 將整合 Clang 用於開發 Windows 程序?
編譯 C++ 項目時模板引發的「undefined reference to」問題?
在哪些領域,C++ 還有著不可替代的優勢?為什麼?
C 語言局部變數,堆與棧的問題?
C++ 內置變數字元串有什麼好的實現思路?

TAG:編程語言 | C編程語言 | C |