被誤解的C++

來源:互聯網
上載者:User


傳統上認為,C++相對於目前一些新潮的語言,如Java、C#,優勢在於程式的運行效能。這種觀念並不完全。如果一個人深信這一點,那麼說明他並沒有充分瞭解和理解C++和那個某某語言。同時,持有這種觀念的人,通常也是受到了某種誤導(罪魁禍首當然就是那些財大氣粗的公司)。對於這些公司而言,他們隱藏了C++同某某語言間的核心差別,而把現在多數程式員不太關心的差別,也就是效能,加以強化。因為隨著cpu效能的快速提升,效能問題已不為人們所關心。這叫“李代桃僵”。很多涉世不深的程式員,也就相信了他們。於是,大公司們的陰謀也就得逞了。
這個文章系列裡,我將竭盡所能,利用一些現實的案例,來戳破這種謊言,還世道一個清白。但願我的努力不會白費。

軟體工程

一般認為,使用Java或C#的開發成本比C++低。但是,如果你能夠充分分析C++和這些語言的差別,會發現這句話的成立是有條件的。這個條件就是:軟體規模和複雜度都比較小。如果不超過3萬行有效代碼(不包括產生器產生的代碼),這句話基本上還能成立。否則,隨著代碼量和複雜度的增加,C++的優勢將會越來越明顯。
造成這種差別的就是C++的軟體工程性。在Java和C#大談軟體工程的時候,C++實際上已經悄悄地將軟體工程性提升到一個前所未有的高度。這一點被多數人忽視,並且被大公司竭力掩蓋。
語言在軟體工程上的好壞,依賴於語言的抽象能力。從面向過程到物件導向,語言的抽象能力有了一個質的飛躍。但在實踐中,人們發現物件導向無法解決所有軟體工程中的問題。於是,精英們逐步引入、並拓展泛型程式設計,解決更高層次的軟體工程問題。(實際上,物件導向和泛型程式設計的起源都可以追溯到1967年,但由於泛型程式設計更抽象,所以應用遠遠落後於物件導向)。
一個偶然的機會,我突發奇想,試圖將貨幣強型別化,使得貨幣類型可以採用普通的算術運算式計算,而無需關心匯率換算的問題。具體的內容我已經寫成文章,放在blog裡:http://blog.csdn.net/longshanks/archive/2007/05/30/1631391.aspx。(CSDN的論壇似乎對大文章有些消化不良)。下面我只是簡單地描述一下問題,重點還在探討語言能力間的差異。
當時我面臨的問題是:假設有四種貨幣:RMB、USD、UKP、JPD。我希望能夠這樣計算他們:
RMB rmb_(1000);
USD usd_;
UKP ukp_;
JPD jpd_(2000);

usd_=rmb_;//賦值操作,隱含了匯率轉換。usd_實際值應該是1000/7.68=130.21
rmb_=rmb_*2.5;//單價乘上數量。
ukp_=usd_*3.7;//單價乘上數量,賦值給英鎊。隱含匯率轉換。
double n=jpd_/(usd_-ukp_);//利用價差計算數量。三種貨幣參與,隱含匯率轉換。
而傳統上,我們通常用一個double或者currency類型表示所有貨幣。於是,當不同幣種參與運算時,必須進行顯式的匯率轉換:
double rmb_(100), usd_(0), ukp_(0), jpn_(2000);

usd_=rmb_*usd_rmb_rate;
ukp_=(usd_*usd_ukp_rate)*3.7;
double n=jpd_/((usd_*usd_jpd_rate)-(ukp_*ukp_jpd_rate))
很顯然,強型別化後,代碼簡潔的多。並且可以利用重載或特化,直接給出與貨幣相關的輔助資訊,如貨幣符號等(這點我沒有做,但加上也不複雜)。
在C++中,我利用模板、操作符重載,以及操作符函數模板等技術,很快開發出這個貨幣體系:
template<int CurrType>
class Currency
{
public:
   Currency<CurrType>& operator=(count Currency<ct2>& v) {

   }
public:
   double _val;

};
template<int ty, int tp>
inline bool operator==(currency<ty>& c1, const currency<tp>& c2) {

}
 
template<int ty, int tp>
inline currency<ty>& operator+=(currency<ty>& c1, const currency<tp>& c2) {

}
template<int ty, int tp>
inline currency<ty> operator+(currency<ty>& c1, const currency<tp>& c2) {

}

總共不超過200行代碼。(當然,一個工業強度的貨幣體系,需要更多的輔助類、函數等等。但基本上不會超過500行代碼)。如果我需要一種貨幣,就先為其指定一個int類型的常量值,然後typedef一下即可:
const int CT_RMB=0;//也可以用enum
typedef Currency<CT_RMB>RMB;
const int CT_USD=1;
typedef Currency<CT_USD>USD;
const int CT_UKP=2;
typedef Currency<CT_USD>USD;
const int CT_JPD=3;
typedef Currency<CT_USD>USD;

每新增一種貨幣,只需定義一個值,然後typedef即可。而對於核心的Currency<>和操作符重載,無需做丁點改動。
之後,我試圖將這個貨幣體系的代碼移植到C#中去。根據實驗的結果,我也寫了一篇文章(也放在blog裡:http://blog.csdn.net/longshanks/archive/2007/05/30/1631476.aspx)。我和一個同事(他是使用C#開發的,對其更熟悉),用了大半個上午,終於完成了這項工作。
令人喪氣的事,上來就碰了個釘子:C#不支援=的重載。於是只能用asign<>()泛型函數代替。之後,由於C#的泛型不支援非類型泛型參數,即上面C++代碼中的int CurrType模板參數的泛型對等物,以及C#不支援泛型操作符重載,整個貨幣系統從泛型程式設計模式退化成了物件導向模式。當然,在我們堅持不懈的努力下,最後終於實現了和C++中一樣的代碼效果(除了那個賦值操作):
assign(rmb_, ukp_);
assign(usd_, rmb_*3.7);

我知道,有些人會說,既然OOP可以做到,何必用GP呢?GP太複雜了。這裡,我已經為這些人準備了一組統計資料:在C#代碼中,我實現了3個貨幣,結果定義了4個類(一個基類,三個貨幣類);重載30個算術操作符(和C++一樣,實現10個操作符,每個類都得把10個操作符重載一遍);6個類型轉換操作符(從兩種貨幣類到第三貨幣類的轉換操作符)。
這還不是最糟的。當我增加一個貨幣,貨幣數變成4個後,資料變成了:5個類;40個算術操作符重載;12個類型轉換操作符重載。
當貨幣數增加到10個後:11個類;100個算術操作符重載;90個類型轉換操作符重載。
反觀C++的實現,3個貨幣時:1個類模板;1個賦值操作符重載模板;10個算術操作符重載模板;外加3個const int定義,3個typedef。
10個貨幣時:1個類模板;1個賦值操作符重載模板;10個算術操作符重載模板;const int定義和typedef分別增加到10個。
也就是說C++版本的代碼隨著貨幣的增加,僅線性增加。而且程式碼增加的係數僅是2。請注意,是程式碼!不是類、函數,也不是操作符的數量。而C#版本的代碼量則會以幾何級數增加。幾何級數!!!
這些數位含義,我就不用多說了吧。無論是代碼的數量、可維護性、可擴充性C++都遠遠好於C#版本。更不用說可用性了(那個assign函數用起來有多難看)。
我知道,有些人還會說:貨幣太特殊了,在實踐中這種情況畢竟少見。沒錯,貨幣是比較特殊,但是並沒有特殊到獨此一家的程度。我曾經做了一個讀取指令碼中的圖形資訊,並繪圖輸出的簡單案例,以展示OOP的一些基本概念,用於培訓。但如果將其細化,可以開發出一個很不錯的指令碼繪圖引擎。其中,我使用了組合遞迴、多態和動態連結,以及類工廠等技術。就是那個類工廠,由於我使用了模板,使得類工厂部分的代碼減少了2/3,而且沒有重複代碼,更易維護。關於抽象類別工廠的GP最佳化,Alexandrescu在其《Modren C++ design》中,有更多的案例。同樣的技術,還可以推廣到業務模型的類系統中,最佳化類工廠的代碼。
如果還不滿意,那麼就去看看boost。boost的很多庫實現了幾乎不可想象的功能,比如lambda運算式、BGL的具名引數等等。它為我們很多最佳化軟體代碼新思路,很多技術和方法可以促進我們大幅最佳化代碼,降低開發成本。
最後,如果你認為C#的最大的優勢在於.net平台,那我可以告訴你,這個世界上還有一種東西叫C++/CLI,完全可以滿足.net的開發,而且更好,足以擦乾淨.net那骯髒的屁股。不過,這將會是另外一個故事了…

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.