簡體   English   中英

來自 Code Complete 關於封裝的 C++ 建議?

[英]C++ advice from Code Complete on encapsulation?

在 Code Complete 的“良好封裝”部分,建議隱藏私有實現細節。 C++ 中給出了一個示例。 這個想法基本上是將接口與實現完全分離,即使在 class 級別。

class Employee {
public:
    ...
    Employee( ... );
    ...

    FullName GetName() const;
    String GetAddress() const;

private:
    EmployeeImplementation *m_implementation;
};

這真的是一種很好的時間利用方式嗎? 這不僅看起來效率低下(這會帶來什么樣的性能損失?),而且代碼完成(“管理復雜性”)的整個座右銘似乎已經被顛倒了——這不會增加復雜性嗎?

PIMPL 習語的另一個優點可能是維護ABI 請參閱實踐中的 The Pimpl Idiom

class 的大小保持不變。 這意味着您可以更改內部實現,同時保持接口不變。

如果實現以編譯形式分發(lib、dll 等),那么,在某些情況下,您可以只替換庫而無需重新編譯使用 class 的代碼。 因此,只要公共接口不變,您就可以將代碼解耦為一個完全獨立的模塊。

正如其他人所說,它還減少了編譯時間,這在某些情況下可能是足夠的理由。

好吧,它確實增加了封裝,因為您的 header 文件現在只包含公共成員和指向私有實現的單個指針。

由於額外的間接級別,它還(稍微?)降低了性能。

“減少編譯時間”是這里的關鍵問題。

如果您(您的公司)是 class 的唯一用戶,那么我認為您沒有任何理由使用這個成語。 您會獲得較低的性能,並且無論如何您都應該每天(或定期)重建源代碼(這應該知道類之間的依賴關系)。

這意味着,如果您是 class 的唯一消費者,那么編譯時間在很大程度上應該是無關緊要的。

如果您正在分發庫,那么情況就完全不同了。 標頭的更改意味着您擁有的任何客戶端都需要重新構建他們的應用程序才能使用您的新版本,即使您所做的是更改 class 的私有部分。 在這里使用 pimpl 成語意味着更改對您的動態庫的用戶是不可見的。

通過指針的額外間接級別可能會導致額外的緩存未命中並減慢程序的速度。 AFAIK,這個習語(PIMPL)最常被建議用來減少編譯時間。 假設您有一個employee.h header 具有class 中的所有字段,而不僅僅是一個指針。 現在,每當您更改員工詳細信息(例如添加或刪除字段)時,包括employee.h在內的每個文件都必須重新編譯。 如果您只有一個指向定義在employee.cpp中的實現 class 的單個指針,那么當您更改EmployeeImplementation時,只需重新編譯employee.cpp

現在,減少的編譯時間值得付出額外的代價嗎? 只有你可以決定。

我認為 pimpl 習慣用法的主要優點(或至少其中一個)不是節省編譯時間,而是允許松散耦合,即打破組件之間的依賴關系。

假設您提供了許多其他組件使用的基礎架構庫。 然后,正如@zvrba 所指出的,每次更改私有實現細節時,所有客戶端都必須重新編譯。 這可能沒什么大不了的,但在大型和復雜的項目中,組件之間的集成可能是一項復雜的任務。 使用 pimpl,如果您的庫是動態的(dll、.so),那么您的客戶不需要任何操作。

這個習語用於對糟糕的標題進行抽象,僅此而已。 僅當定義 class 所需的類型涉及包含泄漏宏的標頭、編譯時間長等時才使用它。除此之外,通常不認為這樣做是正確的。 由於您的實現無論如何都需要動態分配和引用語義,您不妨將其設為接口並提供在 cpp 文件中定義的CreateForMyPlatform()方法。 至少您可以在該場景中使用智能指針。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM