【程序員進階】如何才能減小 C++ 代碼編譯時間的方法!

C++ 的代碼包含頭文件和實現文件兩部分, 頭文件通常是提供給別人使用的, 可是一旦頭文件發生改變,無論多小的變化,全部引用他的文件就必須從新編譯,編譯就要花時間。ios

假如你作的工程比較大(好比二次封裝chrome這類的開發),從新編譯一次的時間就會浪費上班的大部分時間,這樣幹了一天挺累的, 可是你的老闆說你沒有產出,結果你被fired, 是否是很怨啊。因此...程序員

言歸正傳,怎樣介紹編譯時間呢, 我知道的就3個辦法:面試

    ▷ 刪除沒必要要的#include,替代辦法 使用前向聲明 (forward declared )chrome

    ▷ 刪除沒必要要的一大堆私有成員變量,轉而使用 」impl」 方法編程

    ▷ 刪除沒必要要的類之間的繼承函數

爲了講清楚這3點,仍是舉個實例比較好。學習

如今先假設你找到一個新工做,接手之前某個程序員寫的類,以下:spa

//  old.h: 這就是你接收的類

     //

     #include <iostream>

     #include <ostream>

     #include <list>

     // 5 個 分別是file , db, cx, deduce or error , 水平有限沒有模板類

     // 只用 file and cx 有虛函數.

     #include "file.h"// class file

     #include "db.h"// class db

     #include "cx.h"// class cx

     #include "deduce.h"// class deduce

     #include "error.h"// class error

     classold : publicfile, privatedb {

     public:

          old( constcx& );

       db  get_db( int, char* );

       cx  get_cx( int, cx );

       cx& fun1( db );

       error  fun2( error );

       virtualstd::ostream& print( std::ostream& ) const;

     private:

       std::list<cx> cx_list_;

       deduce       deduce_d_;

     };

        inlinestd::ostream& operator<<( std::ostream& os,constold& old_val )

       { returnold_val.print(os);

 }

 

這個類看完了, 若是你已經看出了問題出在哪裏, 接下來的不用看了, 你是高手, 這些基本知識對你來講過小兒科,要是像面試時被問住了愣了一下,請接着看吧指針

先看怎麼使用第一條: 刪除沒必要要的#includecode

這個類引用 5個頭文件, 那意味着那5個頭文件所引用的頭文件也都被引用了進來, 實際上, 不須要引用5 個,只要引用2個就徹底能夠了

一、刪除沒必要要的#include,替代辦法 使用前向聲明 (forward declared )

    ✪ 刪除頭文件 iostream, 我剛開始學習C++ 時照着《C++ primer》 抄,只要看見關於輸入,輸出就把 iostream 頭文件加上, 幾年過去了, 如今我知道不是這樣的, 這裏只是定義輸出函數, 只要引用ostream 就夠了

    ✪ ostream頭文件也不要, 替換爲 iosfwd , 爲何, 緣由就是, 參數和返回類型只要前向聲明就能夠編譯經過, 在iosfwd 文件裏 678行(個人環境是vs2013,不一樣的編譯環境具體位置可能會不相同,可是都有這句聲明) 有這麼一句

typedef basic_ostream<char, char_traits<char> > ostream;

inline std::ostream& operator<<( std::ostream& os,const old& old_val )

{

    return old_val.print(os);

}

 

除此以外,要是你說這個函數要操做ostream 對象, 那仍是須要#include <ostream> , 你只說對了一半, 的確, 這個函數要操做ostream 對象, 可是請看他的函數實現,

裏面沒有定義一個相似 std::ostream os, 這樣的語句,話說回來,但凡出現這樣的定義語句, 就必須#include 相應的頭文件了 ,由於這是請求編譯器分配空間,而若是隻前向聲明 class XXX;編譯器怎麼知道分配多大的空間給這個對象!

看到這裏, old.h頭文件能夠更新以下了:

//  old.h: 這就是你接收的類

     //

     #include <iosfwd>  //新替換的頭文件

     #include <list>

     // 5 個 分別是file , db, cx, deduce or error , 水平有限沒有模板類

     // 只用 file and cx 有虛函數.

     #include "file.h"// class file  , 做爲基類不能刪除,刪除了編譯器就不知道實例化old 對象時分配多大的空間了

     #include "db.h"// class db, 做爲基類不能刪除,同上

     #include "cx.h"// class cx

     #include "deduce.h"// class deduce

     // error 只被用作參數和返回值類型, 用前向聲明替換#include  "error.h" 

     classerror;

     classold : publicfile, privatedb {

     public:

          old( constcx& );

       db  get_db( int, char* );

       cx  get_cx( int, cx );

       cx& fun1( db );

       error  fun2( error );

       virtualstd::ostream& print( std::ostream& ) const;

     private:

       std::list<cx> cx_list_; //  cx 是模版類型,既不是函數參數類型也不是函數返回值類型,因此cx.h 頭文件不能刪除

       deduce       deduce_d_; //  deduce 是類型定義,也不刪除他的頭文件

     };

        inlinestd::ostream& operator<<( std::ostream& os,constold& old_val )

       { returnold_val.print(os); }

 

到目前爲止, 刪除了一些代碼, 是否是心情很爽,聽說看一個程序員的水平有多高, 不是看他寫了多少代碼,而是看他少寫了多少代碼。

若是你對C++ 編程有更深一步的興趣, 接下來的文字你仍是會看的,再進一步刪除代碼, 可是此次要另闢蹊徑了

 

二、刪除沒必要要的一大堆私有成員變量,轉而使用 」impl」 方法

    ✪ 使用 」impl」 實現方式寫代碼,減小客戶端代碼的編譯依賴

impl 方法簡單點說就是把 類的私有成員變量所有放進一個impl 類, 而後把這個類的私有成員變量只保留一個impl* 指針,

代碼以下:

// file old.h

     classold {

        //公有和保護成員

       // public and protected members

     private:

     //私有成員, 只要任意一個的頭文件發生變化或成員個數增長,減小,全部引用old.h的客戶端必須從新編譯

       // private members; whenever these change,

       // all client code must be recompiled

     };

改寫成這樣:

// file old.h

     classold {

     //公有和保護成員

       // public and protected members

     private:

       classoldImpl* pimpl_;

       //  替換原來的全部私有成員變量爲這個impl指針,指針只須要前向聲明就能夠編譯經過,這種寫法將前向聲明和定義指針放在了一塊兒, 徹底能夠。

       //固然,也能夠分開寫

         // a pointer to a forward-declared class

     };

     // file old.cpp

     structoldImpl {

     //真正的成員變量隱藏在這裏, 隨意變化, 客戶端的代碼都不須要從新編譯

       // private members; fully hidden, can be

       // changed at will without recompiling clients

     };

改成impl實現後是這樣的:

// 只用 file and cx 有虛函數.

     #include "file.h"

     #include "db.h"

     classcx;

     classerror;

     classold : publicfile, privatedb {

     public:

          old( constcx& );

       db  get_db( int, char* );

       cx  get_cx( int, cx );

       cx& fun1( db );

       error  fun2( error );

       virtualstd::ostream& print( std::ostream& ) const;

     private:

classoldimpl* pimpl; //此處前向聲明和定義

      };

        inlinestd::ostream& operator<<( std::ostream& os,constold& old_val )

       { returnold_val.print(os); }

//implementation file old.cpp

classoldimpl{

std::list<cx> cx_list_;

deduce        dudece_d_;

};

 

 

三、刪除沒必要要的類之間的繼承

面向對象提供了繼承這種機制,可是繼承不要濫用, old class 的繼承就屬於濫用之一, class old 繼承file 和 db 類, 繼承file是公有繼承,繼承db 是私有繼承,繼承file 能夠理解, 由於file 中有虛函數, old 要從新定義它,可是根據咱們的假設, 只有file 和 cx 有虛函數,私有繼承db 怎麼解釋?! 那麼惟一可能的理由就是:

經過 私有繼承—讓某個類不能看成基類去派生其餘類,相似Java裏final關鍵字的功能,可是從實例看,顯然沒有這個用意,因此這個私有繼承徹底沒必要要,應該改用包含的方式去使用db類提供的功能,這樣就能夠。

把」db.h」頭文件刪除, 把db 的實例也能夠放進impl類中,最終獲得的類是這樣的:

// 只用 file and cx 有虛函數.

     #include "file.h"

     classcx;

     classerror;

     classdb;

     classold : publicfile {

     public:

          old( constcx& );

       db  get_db( int, char* );

       cx   get_cx( int, cx );

       cx& fun1( db );

       error  fun2( error );

       virtualstd::ostream& print( std::ostream& ) const;

     private:

       classoldimpl* pimpl; //此處前向聲明和定義

      };

        inlinestd::ostream& operator<<( std::ostream& os,constold& old_val )

       { returnold_val.print(os); }

//implementation file old.cpp

classoldimpl{

std::list<cx> cx_list_;

deduce        dudece_d_;

};

 

 

小結一下:

這篇文章只是簡單的介紹了減小編譯時間的幾個辦法:

    1. 刪除沒必要要的#include,替代辦法 使用前向聲明 (forward declared )

    2. 刪除沒必要要的一大堆私有成員變量,轉而使用 」impl」 方法

    3. 刪除沒必要要的類之間的繼承

但願這幾條對你有所幫助!


 

最後,無論你是轉行也好,初學也罷,進階也可,若是你想學編程~

【值得關注】個人 C/C++編程學習交流俱樂部!【點擊進入】

問題答疑,學習交流,技術探討,還有超多編程資源大全,零基礎的視頻也超棒~

相關文章
相關標籤/搜索