115
外匯
Way on c & c++ 小記 [五] – 初始化列表與成員函參作用域
初始化列表與成員函參作用域
作者:Jason Lee @https://blog.csdn.net/jasonblog
日期:2010-04-11
[1]初始化列表
所謂初始化列表,從語法角度講,就是構造函數圓括號後的冒號與左花括號之間的緊跟初始值的變量序列,如下是一個示例:
Demo(): b(2), a(b){
作為初始化列表,它以它的作用和初始化順序而出名。
初始化列表有什麼作用呢?我覺得可以一言以蔽之:初始化列表最重要的作用就是用來初始化不能被賦值的成員。比如引用必須在第一次出現的時候進行初始化,之後就不能再被賦值了。另外兩種需要使用初始化列表的是被 const 修飾的類成員以及對象,而後者使用初始化列表進行初始化的主要原因方便和性能上的提高。
雖然初始化列表是一個有序的待初始化的變量序列,但真正對變量進行初始化的順序卻並不是如同初始化列表中所標明的一樣,比如在如下代碼中,是先使用 b (未知數值)初始化 a ,然後再用數值 2 初始化 b :
class Demo { public: Demo(): b(2), a(b){ cout << a << endl << b << endl; }; private: int a,b; };
這是由於在類成員的聲明次序中 a 先於 b 聲明。
進一步反問: a 先於 b 聲明會導致什麼呢?
在詞法分析的過程中,當分析出一個新的變量時,需要向符號表進行該變量的信息注冊。在上述代碼中, a 先於 b 聲明,所以 a 先於 b 被注冊到符號表中。以 Demo 類為例,該類僅有兩個數據成員,並且在該類的符號表中成員 a 是在成員 b 之前。那麼當我們要實例化一個對象(比如 demo )的時候,需要分配一定的內存空間,這時應該思考一下,如果是自己設計會如何進行內存的分配呢?我想,一種合理的方案是根據符號表中各項記錄的信息由上及下進行空間的申請與分配,於是 a 先於 b 獲得了內存空間,那麼自然 a 要先被初始化。
以上隻是一種個人猜想的解釋。另外一種權威的解釋是說為了保證析構函數進行對象消亡處理的效率,必須保證有序性,因為無序性會帶來昂貴的開銷。所以構造函數與析構函數對成員的調用是相反的。
但是如何保證有序呢?我個人覺得對符號表(或者類似機製)的依賴是不可少的,或許,有點殊途同歸?
[2] 成員函參作用域
在類定義體外定義函數,必須指明相關作用域,比如 void Demo::func(){}。
看下麵一段代碼:
#include <iostream> class Demo { public: typedef int index; void func(index); index func2(); private: }; void Demo::func(index arg){ std::cout << arg << std::endl; } Demo::index Demo::func2(){return 0;}; int main(){ Demo demo; demo.func(1); return 0; }
值得注意的是 func 函數後麵的形參 arg 是 index 類型,該類型在 Demo 類中定義,這裏無需特指該類型的定義域。而對於 func2 函數的返回值,該返回值是一個 index 類型,如果沒有指定作用域的話則會出錯。
這是為什麼呢?
以下是個人的理解:
函數具有函數作用域,類也具有類作用域,這種局部作用域是如何體現出來的呢?我想一種可能的方案是采用局部的符號表,而全局作用域則對應著全局符號表。我們都知道,當進入某個函數,相應地就進入到該函數的局部作用域,一個比較常見的例子就是當前的局部變量會覆蓋掉同名的全局變量。
假設當前采用的是符號表的機製,從全局進入某個局部作用域後,當前符號表從全局切換到某個局部符號表。所以當我們在類定義體外定義的成員函數時,首先指明了類作用域,再進入類的成員函數,這時候符號表就切換成與 Demo 類的符號表,從而即可訪問 index 類型,因為該類型在聲明的時候已經注冊到當前的符號表中。
而對於返回類型為 index 的函數 func2 來講,由於返回類型是出現在類成員函數之前,所以如果在類定義體外定義,當前處於符號表,並無該類型的注冊信息,無法查找到,於是就需要指明相關類作用域。
再稍微涉及一點,如果把原語句改動一下:
Demo::index func2(){return 0;}
則該函數是在全局中定義的一個函數,而非類的成員函數。這是因為指明 index 所屬域的時候並沒有進行符號表的切換,所以接下來是將 func2 函數注冊到當前符號表,也就是全局符號表中。這又是為什麼呢?換位思考一下,隻是訪問某個符號表中某個變量的注冊信息值得切換當前符號表嗎?
最後更新:2017-04-02 05:21:03