C 的這五個普遍的誤解,程式設計師的你知道嗎?

2022-07-09 07:30:21 字數 3789 閱讀 9311

1.簡介

本系列包括 3 篇文章,我將向大家展示並澄清關於c++的五個普遍的誤解:

「要理解c++,你必須先學習c」

「c++是一門物件導向的語言」

「為了軟體可靠性,你需要垃圾**」

「為了效率,你必須編寫底層**」

「c++只適用於大型、複雜的程式」

如果你深信上述誤解中的任何乙個,或者有同事深信不疑,那麼這篇短文正是為你而寫。對某些人,某些任務,在某些時間,其中一些誤解曾經只是正確的。然而,在如今的c++,應用廣泛使用的最先進的iso c++ 2011編譯器和工具,它們只是誤解。

我認為這些誤解是「普遍的」,是因為我經常聽到。偶爾,它們有原因來支援,但是它們經常地被作為明顯的、不需要理由的支援地表達出來。有時,它們成為某些場景下不考慮使用c++的理由。

每乙個誤解,都需要一大篇文章,甚至一本書來澄清,但是這裡我的目標很簡單,就是丟擲問題,並簡明地陳述我的原因。

2.誤解1:「要理解c++,你必須先學習c」

不。學習c++基礎程式設計比學習c要容易地多。

c幾乎是c++的乙個子集,但是它不是最先要學習的最好的子集,因為c缺少計數支援,型別安全,和易用的標準庫,而c++為簡單任務提供了這些。考慮乙個拼接email位址的簡單函式:

它可能被這樣使用

而c語言版本需要顯式地字元複製和顯式地記憶體管理:

它可能被這樣使用

哪個版本你更願意教?哪個版本更容易使用呢?剛才我的c版本**寫對了嗎?你確定?為什麼?

最後,哪個版本可能更有效率呢?是的,是c++版本。因為它不需要數引數中字元的個數,也不需要釋放引數中短字串的空間(動態記憶體)。

2.1 學習c++

這不是乙個奇怪的孤立例子。我認為它是典型的。那為什麼有那麼多老師堅持「先學習c」的觀點?

• 因為多年來他們一直這麼做。

• 因為這是課程所要求的。

• 因為老師們年輕時就是這麼學習的。

• 因為c比c++小,就認為c比c++簡單。

• 因為學生們遲早要學習c(或者c++的c子集)。

然而,c並不是最先學習c++的最容易或者最常用的子集。更進一步,一旦你知道了c++的合理數量,c子集很容易學習。先學習c,會導致不斷忍受錯誤,以及學習如何避免這些錯誤,而在c++中很容易避免這些錯誤。

對於用現代的方法教學c++,看我的書programming: principles and practice using c++。它甚至在結尾有一章,專門講如何使用c。它在多個大學中數以萬計的初學者中成功應用。為了靈活學習,這本書的第二版中使用了c++11和 c++14工具。

在c++11[11-12]中,c++對初學者更友好。例如,標準庫中使用元素序列初始化乙個vector:

vectorv = ;

在c++98中,我們只能使用列表來初始化陣列。而在c++11中,我們可以定義乙個建構函式,接收可以是任意需要型別的{}初始化列表。

我們能夠使用range-for迴圈來遍歷vector:

它將對v中的每乙個元素,呼叫一次test()。

range-for迴圈可以遍歷任意序列,因此我們可以直接使用初始化列表來簡化上面的例子:

誤解2:「c++是一門物件導向的語言」

不。c++支援oop和其他程式設計風格,但它並不侷限於狹隘的「物件導向」。它綜合地支援了包括物件導向和泛型程式設計技術。通常,乙個問題的最優解決方案,包含不止一種風格(範例)。「最優」,我指的是最短、最易於理解、最有效率和最易於維護等。

「c++ 是一門物件導向的語言」使人們認為c++不是必要的(當與c做比較時),除非你需要乙個巨大的類繼承層次以及很多須函式(執行時多型)——對很多人和很多問題,這樣應用並不合適。相信這個誤區導致c++因為不是純物件導向而遭到譴責;畢竟,如果你把「好」和「物件導向」等同起來,那麼c++明顯包含了很多不是物件導向的東西,一定會被認為是「不好」。不管是哪種情形,這個誤解為不學習c++提供了乙個很好的藉口。

考慮乙個例子:

它是物件導向的嗎?當然是;它關鍵依賴類的虛函式機制。它是泛型嗎?當然是;它關鍵依賴於乙個引數化容器(vector)和泛型函式for_each。它是函式式嗎?某種程度上;它使用了lambda表示式(構造器)。那麼它到底是什麼?它是現代c++:c++11。

我使用了range-for和標準庫演算法for_each,就是為了炫一下特性。在真實的**中,不管我使用哪種方式,我只會使用一種迴圈。

3.1 泛型程式設計

你想讓這段**更通用嗎?畢竟,它只在指向shapes的指標向量中使用。如果使用列表和內建陣列會怎麼樣?「智慧型指標」(資源管理指標)呢,例如 shared_ptr和unique_ptr?對於那些你可以呼叫draw()和rotate()方法,但是類名稱不是shape的物件呢?考慮:

對於任意你需要從first遍歷到last的序列,它能夠執行。這就是c++標準庫演算法的風格。我使用了auto,來避免不得不對「類似shape的物件」 的介面命名。這是乙個c++11特性,即「使用表示式的型別初始化」,因此對於for迴圈,p的型別由第一次賦值的型別決定。使用auto來表示 lambda引數型別是c++14的乙個特性,但是已經在使用了。

考慮:

這裡,我假設blob是乙個包含draw()和rotate()操作的圖形型別,而container是某種容器型別。標準庫列表(std::list)有成員函式begin()和end(),來幫助使用者遍歷它序列的元素。這是經典的物件導向程式設計。但是如果container不支援c++標準演算法庫遍歷半開序列[b:e]的約定呢?如果不包含begin()和end()成員呢?好了,我還從來沒有見過哪些容器類是不能被遍歷的,因此我們可以定義適當語義的獨立begin()和end()函式。這個標準庫支援c樣式的陣列,因此如果container是c樣式的陣列,問題能夠解決——並且c樣式的陣列仍然很常見。

c/c++的學習裙【105+302+9869】,無論你是小白還是高階者,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多乾貨和技術資料分享!

3.2 適應性

考慮乙個更難的情況:如果容器包含物件指標,而且有著不同的訪問和遍歷模式呢?例如,假設你需要這樣訪問乙個container:

這種風格並非不常見。我們可以把它轉化成乙個[b:e)序列:

注意這種修改方式是非侵入式的:我不需要修改container或者它的繼承類,來把container對映到支援c++標準演算法的遍歷模型。這是一種形式的適應,而不是重構。

我選擇這個例子,是為了展示泛型程式設計技術並不侷限於標準演算法庫(標準演算法中它很常見)。同樣,對大多數常見的「物件導向」定義,它們不是物件導向的。

c++ **必須是物件導向的想法(即到處使用類繼承和虛方法),可能嚴重損壞效率。如果你需要一組型別的執行時解決方案,物件導向程式設計的觀點是偉大的。我就經常使用它。然而,它是相對嚴格的(並不是每個型別都適應類繼承),並且虛方法呼叫抑制了內鏈函式(它可以在一些簡單而重要的場景中降低你50倍的速度)。

做程式設計師的這五年

苦苦攢錢的年輕人 我還在苦苦地攢錢,也許有人不信,我當初一萬二的收入,每個月能存一萬。我花錢不多,也有些克制自己的慾望,但這就導致我很多想做的事情不敢去做。想學結他,想報健身班,想去進修課程,想有段長時間的旅遊等等。都沒有去做,並不是沒有錢去做,而是怕嘗試太費錢,萬一我只是三分鐘熱度呢?可是就是這種...

這該死的程式設計師

喜歡你的工作嗎?有個小姑娘這麼問我,偶像,你喜歡你的工作嗎?我感覺我是其他都不會,沒辦法,才來寫前端的。我思索了一下,回道,談不上喜歡,也談不上討厭,它只是個工作,碰巧會這個而已。她又問,那以後呢?我問,你意思是不喜歡後怎麼辦是嗎?還是說,其實現在就不怎麼喜歡?她說,是啊,現在不怎麼喜歡,然後也就沒...

程式設計師的五個等級

在工作中,什麼樣的程式設計師是乙個好的程式設計師,什麼是乙個差的程式設計師,怎麼劃分,是不是技術好的程式設計師就是好程式設計師,乙個好的程式設計師需要哪些技能,在此樓主結合自己的工作經驗,做一些總結,下面就樓主遇到的程式設計師從低到高來乙個分類 在以上6個方面都做的不錯的,算是最為優秀的程式設計師了...