能否比較一下常見C++開發框架的API風格?

比如Qt、VCL、MFC、Win32……不行說說Android/IOS也行。

看到一篇文章,有感而發

設計Qt風格的C++API


馬一個晚上給你寫 2015年8月17日15:00:00

————————————————————————————————

OK 首先我糾正一下樓主的問題,Win32其實不是什麼C++開發框架,不過我明白題主想說的是Win32 SDK,所謂Win32 SDK其實就是用於windows平台開發的一整套API集合,這套API集合囊括了用於windows平台上面的各個模塊編程的介面(函數),然而這套API集合併不是按照C++調用方式導出的,而是標準的C式函數導出的。因為Windows的整個內核部分都是用C語言完成的,並且上層的Win32子系統部分也是完全的C語言,所以對外提供的編程介面都是C式調用(試想如果對外提供C++的編程介面,那麼就相當於無法使用C語言為這個系統開發軟體,對早期Windows來說簡直是失掉80%的應用軟體。當然誕生先後也有關係,沒記錯的話1985年第一個C++發布,1985年windows 1.0已經發布了)

其次,題主想問常見的C++開發框架,但是提問中卻點出了MFC,我覺得題主應該把平台相關庫和跨平台的庫區分開來,MFC作為Windows平台的特定開發框架,並不應該算作是常見的C++開發框架,同樣的ATL,WTL等都不能算作常見的C++開發框架,MFC,ATL,WTL這些native框架以及.NET,WPF等這些managed框架,以及始於Windows 8,現在又在Windows 10 release的WinRt框架(這個C++,C#,Javascript通吃的)這些都是針對特定Windows 平台的開發框架,你說常見可能也常見,但是並不會被業界強烈要求必須掌握。

關於類庫框架,賣個瓜先:從彙編語言到類庫框架的隨感

而常見的C++開發框架,我覺得應該是:STL,Qt,Boost,VCL(筆者只在Delphi上用過,所以不做介紹了),這些框架都是支持跨平台的,其中這裡面又可以細分一下:

QT作為一個完整的應用程序開發框架,他涵蓋了從GUI到各種基礎庫(IO,網路等等)的所有功能。

而STL和Boost,他們都是不提供GUI開發的基礎功能庫,其中STL提供的功能相比Boost更少。

我舉個簡單的例子,如果你要用這些框架寫一個運行在windows系統上的程序,這個程序有個窗口,有個按鈕,你點擊按鈕就會發送一個UDP包到任意IP,這個程序首先進行UI和業務邏輯分解:

1)一個帶按鈕的窗口UI

2)通過Socket發送UDP報文。你現在的選擇有若干種。

1.純的Win32 SDK(C語言或者C++均可):UI和業務都用Win32 SDK socket

2.MFC(C++):UI和業務都用MFC提供的封裝類庫

3.MFC+Win32 SDK:UI用Win32 SDK,業務用MFC或者對換

4.Win32 SDK + Boost:UI用Win32 SDK,業務用Boost的網路類庫

5.純Qt:UI和業務全部用Qt的封裝類庫

6.Qt + Boost:UI用Qt,業務用Boost

7.Qt + Win32 SDK:UI用QT,業務用Win32 SDK或者對換

當然還有MFC+Qt,MFC+Boost,不過我覺得就算是中國TOP3的架構師這麼用也會被噴死的把

OK,扯了這麼多,我現在一一點一下各個框架的,我也只是初入茅廬,力所能及點到為止,如有不妥之處還望大牛不吝賜教。

Win32 SDK(基本劍術):

其實上面說的那些個組合,如果目標平台一單確定為Windows,那麼他們最終都是被編譯器編譯成了調用Win32 SDK的API的程序,所以Win32 SDK是一切能夠在其上運行的框架的根基,所謂跨平台框架就是,這個框架的實現代碼裡面大量的使用#ifdefine xxxxxx 這樣的宏來判斷當前編譯的目標平台,如過是Windows就調用Windows上的完成對應功能的API,如果是Linux就調用Linux上的對應功能的函數了(這裡僅限C++跨平台,託管代碼JAVA,.NET這種是另外一回事)。這就是Win32 SDK,關於Win32 SDK的更詳細的深層剖析,可以看看筆者的另外一篇老文章:

Windows系統調用架構分析

這篇文章主要順便講了一下API和syscall的概念的區別,對於一般有需求從底層學習的人來說,如果想在Windows系統上發展,Win32 SDK是必不可少的學習過程,這個是能幫你解決一切Windows 問題的根本。

MFC(攻殺劍術):

其實這貨在一個Windows開發者的修鍊過程中,只有階段性的作用,對以後向更高境界的發展有一定程度(僅僅是一定程度)的幫助。MFC這個框架裡面有不少值得學習的設計思想,比如撇開語言提供給的RTTI(當時C++不支持RTTI),消息映射,Command路由等等,GUI方面用框架的類對象封裝Win32 SDK的native對象。其中MFC中最最頻繁的一個思想就是各種「表(table)驅動」(這個也可以說是整個windows系統中的一個被用爛的思想,各種表驅動)。

至於為什麼只是有一定程度的幫助,因為自始至終MFC廣為詬病的一個缺點就是「臃腫不堪」,確實是這樣的,MFC的幾個共享庫對於一個商業軟體來說真的太大了,假如QQ裡面用了MFC(之前確實是用了)安裝包可能要大保守估計四五M,對單個用戶來說沒有任何問題,但是對於TX來說,那個流量就有點影響某些數據的美觀程度了。

所以,MFC適合快速開發一些自用的或者確實不在乎分發的副本大小的軟體程序,一般企業做一些內部支撐還是可以搞搞的(我有個朋友叫套哥,大牛,他跟我吐槽過國內某個最大的視屏聊天公司,後台大部分代碼都是用MFC寫的……估計只有TOP3的架構師才能發現這樣做的優勢!)。但是我們是有更高追求的人,所以了解了解,能熟練的用MFC開發一些中小型軟體就行了,簡歷上就可以寫:能熟練使用沒飯吃進行軟體開發,就OK了,不要留戀,趕緊學下一個技能。

ATL,WTL(刺殺劍術):

上面說到MFC的缺點,MFC的臃腫的缺點暴露是伴隨著COM(請注意:COM只是一種!!思想!!並是不說一提到COM就一定想到他是微軟專門為Windows搞得一套極複雜又過時的框架,微軟提出了COM的模型,然後順便在自己的系統上做出了一個實現版本而已,遵循COM思想可以在任何平台系統自己實現一套COM體系,而且COM確實是在二進位級別實現可重用的極其先進的思想)的發展而日益凸顯的,起初沒有ATL,微軟就給MFC增加了COM和OLE的一些特性,簡化了COM的開發,但是發現用MFC開發的COM組件在網路傳輸中消耗了太多資源,所以決定重新搞一個輕量高效的新框架,所以ATL誕生了。ATL和MFC有一部分代碼是共享的,都是一些公共基礎功能的類庫,比如CString,CRect,CPoint等等。ALT相比MFC的提升就是使用了多繼承和模板,這一點對GUI程序的性能提升尤為明顯,ATL通過多繼承把窗口的屬性,方法和事件處理分離開來。其中比較有代表性的實現是繼承一個實現自身的模板的說起來有點拗口:

class CHelloWnd :

public CWindowImpl& {}

這樣可以到達不用虛函數,而直接在編譯期間生成直接的方法調用,自己體會體會。

還有一個就是thunk技術的使用,其實就是一個跳板,主要解決把WndProc成員方法化,這個要展開說又是一篇長論文,就不展開了。

ATL是目前來說開發windows程序的最高效精簡的框架了。然後WTL,WTL是微軟的一個員工自己寫的,微軟目前也還沒有把這一套模板庫納入官方,WTL就是在ATL的基礎上對Windows的大部分控制項進行了更加有力的封裝,而且方法函數中全部都是直接調用Win32 SDK,有了WTL再來開發windows GUI程序真的是前所未有的方便,所以其實MFC已經可以徹底退休了。

容我睡個覺明天繼續 2015年8月18日00:10:05

————————————————————————————————

接....

昨天碼了這大半篇回頭才發現題主就是問一下API風格,我先在這裡補充一下:

Win32 SDK 是散裝API,可以按照功能模塊劃分為若干個大類,具體的分組方法可以看這裡:

Windows API Index (Windows) 。對於具體的API來說,雖然是C語言,但是仍然離不開「面向對象」的思想,由於C語言本身不提供OO的語言特性,所以OO的實現只能是在系統中去實現。因此很多API的第一個參數都需要提供一個操作對象,這個對象可能是窗口,內核對象句柄,Socket等等,因為是C語言封裝API,所以這些API操作的對象都的具體數據內容都是交由Windows系統去分配和管理的(表驅動,窗口句柄婊,內核對象句柄婊,ATOM婊等等婊),而開發者只需要調用API告訴系統,給我造個風箏(比如一個button控制項),然後把風箏線(句柄handle)給我,然後開發者拿著這個風箏線,繼續通過各種API去控制和設置這個風箏的各種屬性(大小,位置,文字等等)。

HWND mainWnd = CreateWindow();

SetWindowText(mainWnd, _T("xxx"));

SetWindowPos(mainWnd, ...);

GetWindowRect(mainWnd, rc);

DestroyWindow(mainWnd)

這就是典型的Win32 SDK的API風格,因為是C語言,所以遇到需要傳輸複雜類型的數據的時候,只有一種選擇,那就是指針,因為沒有引用這種東西,這就增加內存泄漏的可能性。另外幾乎所有的涉及到字元串的API,都有兩個實現:UNICODE版本和ANSI版本,比如

SetWindowText,其實這不是一個API的名字,只是一個宏,而真正的API名字是

SetWindowTextW,UNICODE版本

SetWindowTextA,ANSI版本

而在開發過程中如果定義了UNICODE(或者UNICODE_)的預處理宏,那麼你寫在代碼裡面的所有SetWindowText都會在編譯期間被宏展開為SetWindowTextW。

而到了MFC,ATL,WTL,已經都使用C++寫的了,所以就直接把風箏線封裝在類中,然後給類加一堆屬性,方法,在調用這些屬性,方法的時候,內部直接就操作本對實例中的風箏線。

題主發的那篇文章:設計 Qt 風格的C++ API,我覺得作者是特別推崇Qt,不過Qt相比MFC這種古董一樣的東西確實有很多優點:

首先,Qt的成員函數明確的劃分了屬性(properties),方法(methods),信號,槽函數,這只不過是OO編程中的基本思想,對象應該具有:屬性,方法,更高一層的有事件,代理。C++是靜態語言,所以Qt搞了個Meta object compiler,然後悄悄地在你寫代碼的同時給你的類插入了一些支持元編程以及RTTI的額外代碼。

在這裡對以下.Net和Qt:

1)首先在成員函數的類別劃分上,基本沒有誰好誰壞之說,但是因為C#語言上支持propertie,而C++只能用函數來模擬propertie,所以Qt在這方面可以說有先天缺陷。

2)其次API參數問題,.NET是C#屬於託管,一個引用打遍天下什麼都不用程序員去考慮,但是Qt是C++,有指針有引用還有直接對象傳參,不同的傳參類型影響安全是一方面,另一方更重要的是對執行效率的影響,一個Vector如果所有API都是用對象傳參,堆棧深度10幾層,每個stack frame都去拷貝一次,時間,空間全部犧牲了。

3)再者,Qt的信號其實相當於C#中的event關鍵字實現的功能,Qt的槽相當於C#的event handler,所不同的是C#語言原生支持delegate,拿到一個event 加加加加加一串handler,相當於Qt中用同一個對象的同一個signal connect了N個對象的slot。Qt是在運行時維護一個Connection列表。而這一切的本質,其實就是我先聲明一個特定簽名的函數,你要是想讓我通知你,那你就按照這個簽名寫個函數,然後把函數指針給我,我會調用你。

上次記得看到一個提問C++語言缺少對象級別的消息傳遞,看到姚老師回答了Qt的Signal/Slot機制,我還是要說,Qt的SS機制已經是在語言級別之上完成的一個功能,跟C++沒有可比性,一個是框架,一個是語言,這真心不能說明Qt是多麼牛逼的框架(實際上我認為Qt裡面很多令人感覺EW的東西,半成品,至少目前沒有完成)。

說到這裡,題主應該明白:

Qt,Boost,STL同屬一類,Boost的signal也是可耐科特來可耐科特去的

.NET, Android那一套屬於一類。

2015年8月19日00:04:51

完結

————————————————————————————————

QT(半月彎刀):

Boost,STL(烈火劍法):


跑個題。作為一個API,在最好的情況下,它的風格只應該由兩個因素決定:

1. 語言和運行時的限制;

2. 業務需求。


  • Qt的所有類使用時, 無需假設任何情況, 直接使用.

比如, ui構造函數里, ui已經可以獲取和設置

  • Qt內部會使用隱藏實現的方法來做, 就是說, 用一個Private的implement, 外層用一個class來調用這個implement. 這樣的好處是, 你無需通過介面或者C API方式來用, 類本身也可以通過派生來override, 所以非常方便

  • 駝峰命名, 還可以接受. 不過屬性不是使用set/get對的命名就有點蛋疼

  • 事件有官方的signal/slot實現, 非常漂亮

  • moc+代碼生成技術, 讓C++瞬間靈活慘了

VCL沒用過

MFC, 經常需要假設資源是否準備好, 判斷不當經常會assert. 20年前的東西, 不要研究也好...


推薦閱讀:

Web API介面如何防止本網站/APP以外的調用?
如何才能寫出簡潔好看的API文檔,有沒有開源框架可以用?
SDK和API的區別?
網站後台要做客戶端API介面,介面文檔如何寫?
有沒有開源的api管理系統?

TAG:開發框架 | API | 編程 | QtC開發框架 | C |