C++類設計和實現的十大最佳實踐

C++程式碼提供了足夠的靈活性,因此對於大部分工程師來說都很難把握。本文介紹了寫好C++程式碼需要遵循的10個最佳實踐,並在最後提供了一個工具可以幫助我們分析C++程式碼的健壯度。原文:10 Best practices to design and implement a C++ class

1。 儘可能嘗試使用新的C++標準

到2022年,C++已經走過了40多個年頭。新的C++標準實際上簡化了許多令人沮喪的細節,提供了新的現代方法來改進C++程式碼,但讓開發人員認識到這一點並不容易。

以記憶體管理為例,這可能是C++中受到最多批評的機制。多年來,物件分配都是由new關鍵字完成的,開發人員一定得記住在程式碼的某個地方呼叫delete。“現代C++”解決了這個問題,並促進了共享指標的使用。

2。 使用名稱空間模組化程式碼

現代C++庫廣泛使用名稱空間來模組化程式碼庫,它們利用“Namespace-by-feature”方法,按功能劃分名稱空間來反映功能集,將單個特性(且僅與該特性)相關的所有內容放到單個名稱空間中。從而使得名稱空間具有高內聚性和高模組化,並且耦合最小,緊耦合的專案被放在了一起。

Boost是按特性分組的最佳示例,其包含數千個名稱空間,每個名稱空間用於對特定的特性進行分組。

3。 抽象

資料抽象是C++中面向物件程式設計最基本和最重要的特性之一。抽象意味著只顯示基本資訊而隱藏細節,資料抽象指的是僅向外部世界提供關於資料的基本資訊,隱藏背景細節或實現。

儘管許多書籍、網路資源、會議演講者和專家都推薦這種最佳實踐,但在很多專案中,這條規則仍然被忽略了,許多類的細節並沒有被隱藏。

4。 類越小越好

具有多行程式碼的型別應該被劃分為一組較小的型別。

需要很大的耐心重構一個大的類,甚至可能需要從頭重新建立所有東西。以下是一些重構建議:

BigClass中的邏輯必須被分成更小的類。這些較小的類最終可能成為巢狀在原始God Class中的私有類,God Class的例項物件由較小巢狀類的例項組成。

較小的類劃分應該由God Class負責的多個職責驅動。要確定這些職責,通常需要查詢與欄位的子集強耦合的方法的子集。

如果BigClass包含的邏輯比狀態多,一個好的選擇是定義一個或幾個不包含靜態欄位而只包含純靜態方法的靜態類。純靜態方法是一種只根據輸入引數計算結果的函式,它不讀取或分配任何靜態或例項欄位。純靜態方法的主要優點是易於測試。

首先嚐試維護BigClass的介面,並委託呼叫新提取的類。最後,BigClass應該是一個沒有自己邏輯的純介面,可以為了方便將其保留,也可以將其扔掉,並開始只使用新類。

單元測試可以提供幫助: 在提取方法之前為每個方法編寫測試,以確保不會破壞功能。

5。 每個類儘量提供最少的方法

包含20個以上方法的類可能很難理解和維護。

一個類有許多方法可能是實現了太多責任的症狀。

也許所面對的類控制了系統中太多的其他類,並且已經超出了應有的邏輯,成為了一個無所不能的類。

6。 加強低耦合

低耦合是理想狀態,可以在應用中進行較少的更改實現程式的某個變更。從長遠來看,可以減少修改、新增新特性的大量時間、精力和成本。

低耦合可以透過使用抽象類或泛型類和方法來實現。

7。 加強高內聚

單一責任原則規定一個類不應該有多於一個更改的理由,這樣的類被稱為內聚類。較高的LCOM值通常可以意味著類的內聚性較差。有幾個LCOM指標,取值範圍為[0-1]。LCOM HS (HS代表Henderson-Sellers)取值範圍為[0-2]。LCOM HS值大於1時需要產生警惕。下面是計算LCOM指標:

LCOM = 1 — (sum(MF)/M*F)

LCOM HS = (M — sum(MF)/F)(M-1)

其中……

M是類中方法的數量(包括靜態方法和例項方法,它還包括建構函式、屬性getter/setter、事件新增/刪除方法)。

F是類中例項欄位的數量。

MF是類訪問特定例項欄位的方法數量。

Sum(MF)是該類所有例項欄位的MF之和。

這些公式背後的基本思想可以表述如下: 如果一個類的所有方法都使用它的所有例項欄位,那麼這個類就是完全內聚的,這意味著sum(MF)=M*F,然後LCOM = 0和LCOMHS = 0。

LCOMHS值大於1就需要警惕了。

8。 只註釋程式碼不能表達的內容

鸚鵡學舌的程式碼註釋沒有為讀者提供任何額外的東西。程式碼庫中充斥著嘈雜的註釋和不正確的註釋,促使程式設計師忽略所有的註釋,或者採取積極的措施隱藏它們。

9。 儘量不要用重複的程式碼

眾所周知,重複程式碼的存在對軟體開發和維護有負面影響。實際上,一個主要缺點是,當為了修復bug或新增新特性而更改重複程式碼的例項時,所有對應的程式碼必須同時更改。

產生重複程式碼最常見的原因是複製/貼上操作,這種情況下,相似的原始碼出現在兩個或多個地方。許多文章、書籍和網站都警告不要採用這種做法,但有時實踐這些建議並不容易,開發人員還是會選擇簡單的解決方案: 複製/貼上大法。

使用適當的工具可以容易的從複製/貼上操作中檢測到重複程式碼,但是,在某些情況下,克隆程式碼很難被檢測到。

10。 不變性有助於多執行緒程式設計

基本上,如果物件在建立之後狀態不變,那麼這個物件就是不可變(immutable)的。如果一個類的例項是不可變的,那麼該類就是不可變的。

不可變物件極大簡化了併發程式設計,這是支援使用它的重要理由。想想看,為什麼編寫適當的多執行緒程式是一項艱鉅的任務?因為同步執行緒訪問資源(物件或其他作業系統資源)是很困難的。為什麼同步這些訪問很困難?因為很難保證多個執行緒對多個物件進行的多次寫訪問和讀訪問之間不會出現競爭條件。如果不再有寫訪問會怎麼樣?換句話說,如果被執行緒訪問的物件的狀態沒有改變會怎麼樣?就不再需要同步了!

關於不可變類的另一個好處是它們永遠不會違反里氏替換原則(LSP, Liskov Subtitution Principle),以下是維基百科對LSP的定義:

Liskov的行為子型別的概念定義了可變物件可替換性的概念,也就是說,如果S是T的子型別,那麼程式中T型別的物件可以被替換為S型別的物件,而不改變該程式的任何期望屬性(例如,正確性)。

如果沒有公共欄位,沒有可以更改其內部資料的方法,並且派生類方法無法更改其內部資料,那麼引用物件類就是不可變的。因為值不可變,所以在所有情況下都可以引用相同的物件,不需要複製建構函式或賦值運算子。出於這個原因,建議將複製建構函式和賦值運算子設為私有,或者從boost::noncopyable繼承,或者使用新的C++ 11特性“顯式預設和刪除特殊成員函式”[2]。

嵌入式物聯網需要學的東西真的非常多,千萬不要學錯了路線和內容,導致工資要不上去!

無償分享大家一個資料包,差不多150多G。裡面學習內容、面經、專案都比較新也比較全!某魚上買估計至少要好幾十。

點選這裡找小助理0元領取:嵌入式物聯網學習資料(頭條)

C++類設計和實現的十大最佳實踐

C++類設計和實現的十大最佳實踐

如何加強對這些最佳實踐進行檢查?

CppDepend[3]提供了名為CQLinq[4]的程式碼查詢語言,可以像資料庫一樣查詢程式碼庫。開發人員、設計人員和架構師可以自定義查詢,以便輕鬆找到容易出現bug的情況。

透過CQLinq,可以結合來自程式碼度量、依賴關係、API使用和其他模型的資料來定義非常高階的查詢,以匹配容易出現bug的情況。

例如,分析clang原始碼後,可以檢測到大類:

C++類設計和實現的十大最佳實踐

檢測到有大量方法的類:

C++類設計和實現的十大最佳實踐

或者檢測到內聚性較差的類:

C++類設計和實現的十大最佳實踐

References:

[1] 10 Best practices to design and implement a C++ class: https://issamvb。medium。com/10-best-practices-to-design-and-implement-a-c-class-4326611827e1#:~:text=10%20Best%20practices%20to%20design%20and%20implement%20a,class%20as%20you%20can。%20。。。%20More%20items。。。%20

[2] Explicitly defaulted and deleted special member functions: http://en。wikipedia。org/wiki/C%2B%2B11#Explicitly_defaulted_and_deleted_special_member_functions

[3] CppDepend: http://www。cppdepend。com/

[4] CQLinq: https://www。cppdepend。com/cqlinq

- END -

文章連結:https://mp。weixin。qq。com/s/4ZlMrY7gDcZPxitvFuz7oQ

轉載自:俞凡 程式喵大人

文章來源:C語言與CPP程式設計

文章連結:C++類設計和實現的十大最佳實踐

版權申明:本文來源於網路,免費傳達知識,版權歸原作者所有。如涉及作品版權問題,請聯絡我進行刪除。