首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

Effective C++ 條款 34:將編譯依賴降至最低——接口與實現分離術

     編輯:C++ 入門

Effective C++ 條款 34:將編譯依賴降至最低——接口與實現分離術

在大型 C++ 專案中,編譯依賴管理至關重要。當修改類的實現細節(私有成員、私有函數)而非接口時,理想情況下不應觸發依賴此類的所有文件重新編譯。然而 C++ 的編譯模型導致「頭文件包含定義」,任何實現變更都會連鎖觸發重編譯。本文探討兩種經典技術——句柄類與協議類——實現接口與實現的物理分離。

問題根源:定義依賴 vs 聲明依賴

若頭文件包含 #include "ClassA.h",則使用該頭文件的所有文件都依賴 ClassA 的完整定義。一旦 ClassA 的私有成員變動,所有依賴文件必須重編。解決關鍵在於:用類聲明替換類定義,將 #include 移至實現文件。

技術一:句柄類 / 信封類

核心思想:接口類僅持有一個指向實現類的指針,所有操作轉發給實現類。

// ClassC.h - 接口類(用戶看到的)
class ClassA; class ClassB; class ClassCImpl; // 僅前向聲明
class ClassC {
public:
    ClassC(const ClassA&, const ClassB&);
    virtual ~ClassC();
    int getA() const;
    double getB() const;
    double getC() const;
private:
    ClassCImpl* impl; // 指向實現的不透明指針
};

// ClassC.cpp - 接口實現
#include "ClassC.h"
#include "ClassCImpl.h" // 此處才包含實現定義
ClassC::ClassC(const ClassA& a, const ClassB& b) : impl(new ClassCImpl(a,b)) {}
ClassC::~ClassC() { delete impl; }
int ClassC::getA() const { return impl->getA(); }
// ... 其他轉發函數

// ClassCImpl.h - 實現類(隱藏細節)
#include "ClassA.h"
#include "ClassB.h"
class ClassCImpl {
    ClassA A; ClassB B; ClassB C; // 真實數據成員
public:
    ClassCImpl(const ClassA&, const ClassB&);
    int getA() const; double getB() const; double getC() const;
};

優點:修改 ClassCImpl 任何私有細節,用戶代碼無需重編。缺點:額外指針間接訪問與動態分配開銷。

技術二:協議類 / 抽象基類

接口類純化為抽象基類:無數據成員、無構造函數、擁有虛析構函數與純虛函數。對象創建通過工廠函數返回派生類指針。

// ClassD.h - 協議類
class ClassA; class ClassB;
class ClassD {
public:
    virtual ~ClassD() {}
    virtual int getA() const = 0;
    virtual double getB() const = 0;
    virtual double getD() const = 0;
    static ClassD* makeClassD(const ClassA&, const ClassB&); // 工廠函數
};

// RealClassD.h - 具體實現
#include "ClassA.h" #include "ClassB.h" #include "ClassD.h"
class RealClassD : public ClassD {
    ClassA A; ClassB B; ClassB D;
public:
    RealClassD(const ClassA&, const ClassB&);
    int getA() const override; // ... 實現純虛函數
};

// RealClassD.cpp - 工廠函數定義
#include "RealClassD.h"
ClassD* ClassD::makeClassD(const ClassA& a, const ClassB& b) {
    return new RealClassD(a, b);
}

用戶代碼:ClassD* d = ClassD::makeClassD(a,b); d->getD(); 動態綁定實現多態,實現變更僅需重編派生類 cpp。

權衡與工程建議

兩種技術均以時間/空間開銷換取編譯防火牆。句柄類適合單一實現場景,協議類支援多態多實現。專案成熟期可考慮用具體類替換以消除開銷。核心原則:頭文件盡量少包含其他頭文件,多用前向聲明。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved