C語言:編程語言齊聚,我發現只有我沒有對象

☄ 聚會

C語言春節回家過年,遇到了不少小夥伴:Java , Python, JavaScript,Ruby......

大家在大城市發展得都不錯,回到老家,聚到一起吃飯, 談天說地,都是喜氣洋洋。

老練的Java則是一直拿TIOBE排行榜說事兒:“高處不勝寒啊!”

雖然常年排名TIOBE第二,C語言有點黯然神傷,人類用自己寫的程序可真不少,可都是處於底層,在系統級編程,什麼操作系統,數據庫,編譯器...... 與應用層比起來,沒那麼光鮮亮麗。

現在很多人培訓了Python、Java 就說自己會編程了, 不懂指針,不懂內存,不懂底層的基本原理, 那能算會編程嗎?

C語言開始憤憤不平,悶頭吃菜,似乎要把這股鬱悶之氣發洩到美味佳餚上去。

觥籌交錯之間,Java 摟住C的肩膀,親切地說:“兄弟,你有對象了嗎?”

這下可捅了馬蜂窩,大家的眼光齊刷刷地聚集到C語言的身上。

C嚅囁了半天:“沒...... 沒有。”

“哈哈哈...... 我們都有對象,你這麼大了還沒對象?!” Python笑道。

“是啊,一個沒有對象的編程語言還有什麼前途?”JavaScript補刀,他原來沒有class的概念,是通過“原型”實現的OOP,最近幾年才在語法層面引入class關鍵字。

“我雖然沒有對象,但是有指針啊,功能非常強大。”

“指針?你說的是那容易出錯的指針嗎? 現在有誰用指針啊?” JavaScript說道。

“不會用指針,就不是真正的程序員!” C語言漲紅了臉。

餐桌的氣氛變得有些尷尬,捅了簍子的Java招呼著說:“來來來,繼續喝酒。”

好不容易熬到聚餐結束,C語言回到了自己的家,家裡冷冷清清,自己的“親爹”丹尼斯·裡奇(Dennis Ritchie),有史以來最偉大的程序員之一, 已經於2011年10月不幸去世。

桌子上擺著的一本《C程序設計語言》,那是丹尼斯·裡奇唯一的遺著, 拿起這本書,C不由悲從心來。

C語言:編程語言齊聚,我發現只有我沒有對象

☄ 串門

C語言突然想起來對門的 Ken Thompson,那是Dennis Ritchie的“好基友”,他們倆一起創造了偉大的Unix操作系統,獲得了計算機界的最高獎:圖靈獎。

要不問問Ken? 為什麼不讓我有對象?不讓我面向對象編程!

C來到Ken Thompson的門口,按了門鈴,門開了,C語言一眼就看到Ken Thompson正在和Go玩得不亦樂乎,心中更是悽苦,Go才是人家的親兒子,我算老幾, 轉身便要離去。

Ken 卻從後面叫住了他:“小C啊,快進來,和你的兄弟Go玩一會兒。”

看到C滿臉沮喪,Ken也大為吃驚:“大過年的,怎麼回事?”

C不滿地說:“當年你們為什麼不讓我有對象?”

“對象,什麼對象? 奧,你是說面向對象編程吧!其實吧你親爹把你設計出來,主要是做系統級編程的,要的是貼近硬件,要的是效率,要那複雜玩意兒幹啥?中看不中用,再說了,你和Go一樣,不是有struct嗎? ” Ken 轉向Go,擠了擠眼睛。

“是啊是啊,struct很好用的!” Go馬上附和。

“但是struct也實現不了OOP啊, Python,JavaScript他們都嘲笑我! ”

“那你說說,什麼是OOP?”Ken問道。

“嗯,就是封裝、繼承、多態吧? ” C回答到。

“好,我來給你掰扯掰扯,用C語言怎麼實現封裝、繼承還有多態!”

☄ 封裝

Ken Thompson 真不愧是老司機,唰唰唰迅速就寫成了一段代碼。

他說道:“我們先來說說封裝,這封裝就是把信息給隱藏起來,你先看看這段代碼。”

shape.h

C語言:編程語言齊聚,我發現只有我沒有對象

shape.c

C語言:編程語言齊聚,我發現只有我沒有對象

main.c

C語言:編程語言齊聚,我發現只有我沒有對象

這裡定義了一個叫做Shape的結構體,外界只能通過相關的函數來對這個Shape進行操作,例如創建(Shape_create), 移動(Shape_move), 還有獲取位置(Shape_getX)等,不能直接訪問Shape的內部數據結構。

雖然這裡沒有class這樣的關鍵字,數據結構和相關操作是分開寫的,看起來不太完美, 但確實是實現了封裝。

C語言:編程語言齊聚,我發現只有我沒有對象

C 看到Ken Thompson居然把那個指針的名稱叫做self,和Python的相同,不由得笑了起來:“我明白了,那繼承該怎麼做呢?

☄ 繼承

Ken Thompson不吭聲,繼續寫代碼。

大牛的風格看來都是類似的: 別瞎BB,給我上代碼。

C語言:編程語言齊聚,我發現只有我沒有對象

這次定義了一個矩形(Rectangle)的結構體,其中嵌套了Shape,難道這就實現了繼承? C有點疑惑。

Go小子在旁邊叫了起來:“我明白了,在內存中,他們是這樣的。”

C語言:編程語言齊聚,我發現只有我沒有對象

通過這種組合的方式,也算是實現了繼承吧。

C語言:編程語言齊聚,我發現只有我沒有對象

☄ 多態

這麼輕鬆就實現了封裝和繼承,C語言感到很興奮, 但是多態怎麼實現呢?

這時候又傳來了門鈴聲,Linus大神拎著一瓶酒進來,要找C小夥兒喝酒,看到這桌子上的代碼,立刻就明白了怎麼回事。

他說道:“別整那麼多花裡胡哨的東西,還多態,不就是函數指針嘛! 我給你舉個例子。”

C語言:編程語言齊聚,我發現只有我沒有對象

“這個結構體包含了兩個函數指針,一個用來計算圖形的面積,另外一個把這個圖形畫出來。我們把這個結構體叫做虛函數表。”

“這有什麼用啊?”

“在你的Shape中,添加一個指向該函數表的指針就行了。” Linus回答。

C語言:編程語言齊聚,我發現只有我沒有對象

C和Go都是一臉茫然。

“蠢材, 你們想想啊,當你創建一個子類對象的時候,比如Rectangle, 把那個虛函數指針vptr指向另外一組函數,會怎麼樣?”

兩人還是不懂,Linus只好繼續畫圖:

C語言:編程語言齊聚,我發現只有我沒有對象

現在C有點明白了, 無論是Rectangle對象,還是Square對象,在調用Shape_area方法的時候, 都需要通過vptr這個指針找到虛函數表中的area方法,對於Rectangle,找到的是Rectangel_area方法,對於Square,找到的是Square_area方法。

struct Rectangle *r = Rectangle_create(5,5,10,10);

Shape_area((struct Shape *) r);

“其實吧,你的兄弟C++的多態實現原理也是類似的!在運行時查找真正的函數去執行。” Ken 總結到。

“對,這種函數指針的使用方法太常見了,在我的Linux操作系統中也會定義類似的東西” Linus接口道,

C語言:編程語言齊聚,我發現只有我沒有對象

“只要IO設備提供這幾個函數的實際定義,就可以將File結構體的函數指針指向對應的實現,那就實現了用同一套接口操作不同的IO設備。”

C語言高興起來:“哈哈,我就說我的指針很厲害吧,這些全是通過指針來實現的。”

“是啊,別聽Java, Python, JavaScript他們瞎BB,你也有對象,也能進行面向對象的編程!”

C語言說道:“走,喝酒去!”

來自C語言的忠告:對於熱愛編程的小夥伴來說,一個好的學習氛圍很重要!如果你感興趣或者有需求的話,筆者有一個編程零基礎入門學習交流俱樂部,私信我【編程學習】自動獲取進入學習!還有完整的學習路線圖和學習文件視頻,歡迎想學編程的小夥伴們!

C語言:編程語言齊聚,我發現只有我沒有對象



分享到:


相關文章: