1. 程式人生 > >c++ 編譯期與執行期總結

c++ 編譯期與執行期總結

一 見識編譯期的力量

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include "stdafx.h" #include <iostream> using namespace std; class A{ public: virtual void f(){ cout << "A" << endl; } }; class B :public A { private: void f(){ cout << 
"B" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A *pA = new B(); pA->f(); return 0; }

出現了很有趣的結果,在main函式中,訪問到了B類中的私有方法。為什麼會出現這樣的結果呢?

一般來說外部物件訪問類的私有成員,除非是友元,否則在編譯的時候就會報錯,但是上面那段程式碼卻可以正常的編譯通過。

C++因為支援面向物件程式設計,制訂了一系列實現策略的語言機制。其中,各種各樣的“限制”主要是出現在編譯時:因此如果直接B d; d.f(); 就會導致編譯錯誤:編譯器發現  

B::f()是B類的私有成員函式,因此拒絕這樣的訪問。

這裡我們可以區分類和物件:編譯期的概念,也是“訪問許可權”、“成員資料”、“成員函式”這幾個概念的“作用域”。而物件的作用域是執行期。它包括類的例項、引用和指標。  

參考:編譯執行

  A    *pA    =    new    B();      這裡    pA    是一個    A* , 所以就作為一個A類的指標參與了編譯;

因此從pA呼叫f()在編譯器眼中,就是呼叫了A類的公開成員函式f()因此通過編譯;然後在執行時,由於多型作用pA呼叫的f()是派生類的f()成員函式。

雖然這時f()是private成員函式,但是由於    private/public    這些訪問控制是編譯時的限制,在執行時無效,所以B::f() 被成功呼叫。

如果能夠理解這兩個在不同時間作用的概念,這個問題就很好理解.

2 上面的例子是轉載的,裡面有個例子是輸出除錯資訊的,

1)

const bool g_debug=1

void Log(char* str) {   

  if (g_debug){      

printf(str);

}

}

2) #define DEBUG

#ifdef DEBUG

#define LOG(m) \

{\    

printf(m);

\ }\

#else

#define LOG(m)

#endif

有經驗的程式設計師肯定一眼就看出來第二種Log輸出方式比較好。第一種的判斷是在執行期,而第二種的判斷是在編譯期。第一種在每次執行log函式的時候都會去判斷全域性變數,

而第二種是在編譯的時候就已經將不需要的Log資訊定義為空。因為編譯消耗的時間是一次性的,而執行的效率是直接呈現給使用者的。由這種節約時間的方法,

我們可以發現把很多函式的判斷和計算放在編譯期,會大大節約執行的時間,提供執行效率,但是編譯器並不是萬能,所以編譯期能做的工作還是十分的有限。

二 編譯期 執行期 說明

1. 編譯期是指把你的源程式交給編譯器編譯的過程,最終目的是得到obj檔案,連結後生成可執行檔案預處理、編譯、彙編和連線執行期指的是你將可執行檔案交給作業系統(輸入檔名,回車)執行、直到程式執行結束。執行的目的是為了實現程式的功能 。

2.編譯期分配記憶體,就是用靜態或全域性陣列。這是在編譯的時候確定的。

編譯期記憶體錯誤,就是比如某個資料段DATA段或者CODE段等等,超過跑這個程式的目標機的儲存器的限制。比如DOS下,DATA段不能超過64K吧。

執行期分配記憶體,就是用malloc()之類的函式,在堆上分配記憶體。    執行期記憶體錯誤,就是執行的時候發生的,比如申請不到記憶體,記憶體越界訪問,等等。

除了記憶體外,編譯器還做了巨集替換,檢查型別安全,上面一說的,類的“訪問許可權”、“成員資料”、“成員函式”這幾個概念的“作用域”等等的語法檢查,其他的我就不知道了。

三 編譯期執行的效率

編譯期,把每一步操作結果的值都給快取下來了,效率當然高了,我們使用相同的快取策略也可以縮短函式的執行時間。

執行期執行的函式則沒有這個優點,它和普通的函式沒有區別,不同點在於它在編譯的時候執行。把編譯器看成一種動態語言執行環境,那麼編譯“編譯期執行的函式”的過程就像是執行動態語言程式的過程。

如果程式中存在大量編譯期執行函式,可能極大地降低編譯效率,對於它的使用應該儘量避免。

模板提供的是一種宣告式語法,在複雜的靜態執行邏輯面前有時候會顯得力不從心,編譯期執行函式在解決這個問題的同時,卻帶來了上面這種副作用。

如果能把兩者的優點結合起來用函式的語法來寫程式,由編譯器生成優化的模板程式碼,這種編譯期執行才可以大量使用。

同樣,可以寫個梯乘的函式,求10000,在編譯器和執行期,各寫一個例子看看執行結果。就知道編譯期做運算的好壞。

四 模板的運用 1 stl 模板是在編譯期執行的,所以程式中儘量用stl,除了安全性與規範性好外,stl的一些操作都在編譯時執行。

2 ATL ATL 跟com有個區別就是用了模板來取代com的虛擬表。ATL用了大量模板,很多操作都在編譯時執行了, 所以編出來的可執行檔案,比較小。這個是我自己猜的。

3 泛型程式語言,C++強大(但容易失控的)模板功能使它能在編譯期完成許多工作,從而大大提高執行期效率。這個東西比較難,暫時沒詳細瞭解。一個不錯 的例子: