91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

《Effective C++》之條款31:將文件間的編譯依存關系降至最低

發布時間:2020-07-29 08:50:22 來源:網絡 閱讀:649 作者:313119992 欄目:編程語言

《Effective C++》

條款31:將文件間的編譯依存關系降至最低

       假設你對C++程序的某個class實現文件做了些輕微修改。注意,修改的不是class接口,而是實現,而且只改private成分。然后重新建置這個程序,預計只花數秒就好。畢竟只有一個class被修改。當你按下“Build”按鈕或鍵入make指令時,會大吃一驚,然后感到困窘,因為你意識到整個世界都被重新編譯個連接了!那么問題出在哪里呢???

問題出在C++并沒有把“將接口從實現中分離”這事做的很好。Class的定義式不只詳細描述了class接口,還包括十足的實現細目。例如:

#include <string>
#include "date.h"
#include "address.h"
class Person
{
public:
    Person(const std::string& name,const Date& birthday,
           const Address& addr);
    std::string name() const;
    std::string birthDate() const;
    std::string address() const;
    ...
private:
    std::string theName;//實現細目
    Date theBirthDate;//實現細目
    Address theAddress;//實現細目
};

其中:

#include <string>
#include "date.h"
#include "address.h"

       由于這些頭文件,使得Person定義文件和其含入文件之間形成了一種編譯依存關系。如果這些頭文件中有任何一個被改變,或這些頭文件所依賴的其他頭文件有任何改變,那么每一個含入Person class的文件就得重新編譯,任何使用Person class的文件也必須重新編譯。這樣的連串編譯依存關系會對許多項目造成難以形容的災難。

如下是一個解決方案的思路:

將對象實現細目隱藏于一個指針背后。把Person分割成兩個classes,一個只提供接口,另一個負責實現該接口。如果負責實現的那個所謂implementation class 取名為PersonImpl,Person將定義如下:

#include <string>
#include <memory>

class PersonImpl;//Person實現類的前置申明
class Date;//Person接口用到的classes(Date,Address)的前置申明
class Address;

class Person
{
public:
    Person(const std::string& name,const Date& birthday,
           const Address& addr);
    std::string name() const;
    std::string birthDate() const;
    std::string address() const;
    ...
private:
    std::tr1::shared_ptr<PersonImpl> pImpl;//智能指針shared_ptr,指向實物
};

這個分離的關鍵在于以“申明的依存性”替換“定義的依存性”,那正是編譯依存性最小化的本質:現實中讓頭文件盡可能自我滿足,萬一做不到,則讓它與其他文件內的申明式相依。其他每一件事都源自于這個簡單的設計策略:

1.如果使用object reference或object pointers可以完成任務,就不要使用objects。

2.如果能夠,盡量以class申明式替換class定義式。

3.為申明式和定義式提供不同的頭文件。


Handle classes其中具體做法1是將他們的所有函數轉交給相應的實現類并由后者完成實際工作。例如下面是Person兩個成員函數的實現:

#include "Person.h"
#include "PersonImpl.h"

Person::Person(const std::string& name,const Date& birthday,
               const Address& addr)
               : pImpl(new PersonImpl(name,birthday,addr))
{ }

std::string Person::name() const
{
    return pImpl->name();
}

請注意,Person構造函數以new調用PersonImpl構造函數,以及Person::name函數內調用PersonImpl::name。這是重要的,讓Person變成一個Handle class并不會改變它做的事,只會改變它做事的方法。

另一個制作Handle class的辦法是,令Person成為一種特殊的abstract base class,稱為interface class。這種class的目的是詳細一一描述derived classes的接口,因此它通常不帶成員變量,也沒有構造函數,只有一個virtual析構函數以及一組pure virtual函數,用來描述整個接口。


總結:

  1. 支持“編譯依存性最小化”的一般構想是:相依于申明式,不要相依于定義式。基于此構想的兩個手段是Handle classes和Interface classes。

  2. 程序庫頭文件應該以“完全且僅有申明式”的形式存在。這種做法不論是否設計template都適用。

2016-11-08 23:10:40

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

津南区| 上饶县| 凌海市| 杭锦旗| 宜宾县| 岗巴县| 射洪县| 黄梅县| 洛阳市| 松原市| 新闻| 资中县| 渑池县| 辽阳市| 城市| 瑞丽市| 廉江市| 军事| 察雅县| 顺昌县| 马尔康县| 错那县| 中西区| 广东省| 洱源县| 浪卡子县| 新和县| 青浦区| 万安县| 北海市| 柞水县| 彝良县| 京山县| 原阳县| 瑞安市| 寿宁县| 农安县| 措美县| 武陟县| 南和县| 新化县|