關於const修飾的引用作為引數傳遞和non-member, non-friend函式

licup123發表於2009-01-06
1. 關於引用。
引用本身就意味著“不進行復制”,它只是一個別名罷了,所以不會有構造和析構的開銷。這與是否使用了const是無關的。

注意即使是const引用,也不保證“不修改資料”。這可以從兩個方面來理解。
一方面,C++存在一個關鍵字mutable,用它修飾的類成員,即使在const成員函式中也是可以修改的。
舉例來說,你實現了一個類,用它表示硬碟,則在對它進行讀取時,可能希望把這個read函式定義為const成員函式,因為讀取資料之時並不會修改到硬碟中的資料。然而現實並不是那麼完美。你的硬碟是帶緩衝區的,在讀取之時可能會修改到緩衝區的資料,這與前面的const發生了矛盾。一種解決辦法就是把緩衝區資料宣告為mutable,這樣即使在const成員函式中也可以對它進行修改。
另一方面,C++還提供了一個const_cast。雖然一般用不到,但正所謂“只要有可能犯錯,就會有人犯錯”,一旦把一個const引用轉化為non-const引用,“無法修改”這個限制都成為了空談。

可見const引用也有修改資料的可能(雖然可能性極其的小)。
因此,為const引用複製一份資料的做法不僅是低效的,而且還是錯誤的。



2. 關於non-member, non-friend函式。
用不著想那麼多,std::vector本身就是很好的例子了。
std::vector功能不少。可以線性的儲存資料,各元素緊密排列,可以動態增長,可以修改插入刪除等等等等。但是它也並沒有包羅永珍。比如排序,比如查詢,這些操作都沒有作為成員函式來提供,而是用了non-member, non-friend的函式。

為什麼要將排序等操作單獨列出來,而不再作為成員函式呢?因為設計者認為,std::vector的成員函式已經“足夠多”了。這些函式已經構成了一組“完備”的操作集。即是說,其它的操作完全可以通過現有的成員函式,利用各種組合來實現。為此,沒有必要再繼續的增加成員函式的數量。
從維護的難度上看,如果std::vector提供排序的功能,則當std::vector的實現被修改時,其排序的程式碼難免也要被修改。但正如我們現在所看到的,無論std::vector的實現如何修改,std::sort卻可以始終如一,這正是non-member, non-friend函式的優勢。

以模組的觀點來看,std::vector是“可變長度的陣列”模組,而排序是屬於“演算法”的模組,兩者沒有必要放在一起(若讓排序成為std::vector的成員函式,則顯然是放在一起了)。在進行模組設計之時,總的原則就是外鬆內緊。即模組之間的聯絡儘可能的少,模組內部各事物的聯絡則往往非常的多。

當然了,具體的設計總是見仁見智。哪些功能放在同一模組,哪些功能放在不同模組,這個沒有標準做法,尺度只有靠設計者自己把握。
有的設計也確實把排序和可變陣列做到了同一個class之中,這也並不是錯誤。我確實可以舉出例子。比如Irrlicht(一個開源的遊戲引擎),它就有一個集合了可變陣列和排序功能的類。
一切都是根據需要,沒有最正確的,只有最合適的。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10697500/viewspace-528620/,如需轉載,請註明出處,否則將追究法律責任。

相關文章