標籤:ons head 成員 complete template ror ref ati use
可以在另一個類內部定義一個類,這樣的類是嵌套類,也稱為巢狀型別。嵌套類是獨立的類,基本上與它們的外圍類不相關,外圍類對嵌套類的成員沒有特殊訪問權,並且嵌套類對其外圍類的成員也沒有特殊訪問權。
嵌套類的名字在其外圍類的範圍中可見,但在其他類範圍或定義外圍類的範圍中不可見。嵌套類的名字將不會與另一範圍中聲明的名字衝突。
嵌套類定義了其外圍類中的一個類型成員。像任何其他成員一樣,外圍類決定對這個類型的訪問。在外圍類的 public 部分定義的嵌套類定義了可在任何地方使用的類型,在外圍類的 protected 部分定義的嵌套類定義了只能由外圍類、友元或衍生類別訪問的類型,在外圍類的 private 部分定義的嵌套類定義了只能被外圍類或其友元訪問的類型。
1:例子
template <class Type> class Queue {public: ... private: // public members are ok: QueueItem is a private member of Queue // only Queue and its friends may access the members of QueueItem struct QueueItem { QueueItem(const Type &); Type item; QueueItem *next; }; QueueItem *head; QueueItem *tail;};
因為 QueueItem 類是 private 成員,所以只有 Queue 類的成員和友元可以使用 QueueItem 類型。使 QueueItem 類成為 private 成員之後,就可以使QueueItem 成員 public。
因為 Queue 類是一個模板,它的成員也隱含地是模板。具體而言,嵌套類QueueItem 隱含地是一個類模板。像 Queue 類中任何其他成員一樣,QueueItem的模板形參與其外圍類(Queue 類)的模板形參相同。
在其類外部定義的嵌套類成員,不能定義在外圍類內部,必須定義在定義外圍類的同一範圍中。
成員的名字在類外部是不可見的。要定義QueueItem的建構函式,必須指出,QueueItem 是 Queue 類範圍中的嵌套類:
template <class Type>Queue<Type>::QueueItem::QueueItem(const Type &t):item(t), next(0) { }
這段代碼定義了一個函數模板,以名為 Type 的單個類型形參化為形參。從右至左讀函數的名字,這個函數是 QueueItem 類的建構函式,QueueItem 類嵌套在Queue<Type> 類的範圍中。
如果 QueueItem 類聲明了一個靜態成員,它的定義也需要放在外層範圍中。假定 QueueItem 類有一個靜態成員,它的定義看起來可能像下面這樣:
template <class Type>int Queue<Type>::QueueItem::static_mem = 1024;
執行個體化外圍類模板的時候,不會自動執行個體化類模板的嵌套類。像任何成員函數一樣,只有當在需要完整類類型的情況下使用嵌套類本身的時候,才會執行個體化嵌套類。例如,像Queue<int> qi; 這樣的定義,用 int 類型執行個體化了 Queue 模板,但沒有執行個體化QueueItem<int> 類型。成員 head 和 tail 是指向 QueueItem<int> 指標,這裡不需要執行個體化 QueueItem<int> 來定義那個類的指標。只有當 Queue<int> 類的成員函數中對 head 和 tail 解引用的時候,才執行個體化 Queue<int> 類。
2:名字尋找
對嵌套類中所用名字的名字尋找在普通類的名字尋找之前進行,現在唯一的區別是可能要尋找一個或多個外圍類範圍。
作為嵌套類中名字尋找的例子,考慮下面的類聲明:
class Outer {public: struct Inner { // ok: reference to incomplete class void process(const Outer&); Inner2 val; // error: Outer::Inner2 not in scope }; class Inner2 { public: // ok: Inner2::val used in definition Inner2(int i = 0): val(i) { } // ok: definition of process compiled after enclosing class is complete void process(const Outer &out) { out.handle(); } private: int val; }; void handle() const; // member of class Outer};
編譯器首先處理 Outer 類成員的聲明 Outer::Inner 和 Outer::Inner2。
將名字 Outer 作為 Inner::process 形參的使用被綁定到外圍類,在看到process 的聲明時,那個類仍是不完整的,但形參是一個引用,所以這個使用是正確的。
資料成員 Inner::val 的聲明是錯誤的,還沒有看到 Inner2 類型。
Inner2 中的聲明看來沒有問題——它們大多隻使用內建類型 int。唯一的例外是成員函數 process,它的形參確定為不完全類型 Outer。因為其形參是一個引用,所以 Outer 為不完全類型是無關緊要的。
直到看到了外圍類中的其餘聲明之後,編譯器才處理建構函式和 process成員的定義。
當編譯器尋找 Inner2 類中的定義所用的名字時,Inner2 類和 Outer 類中的所有名字都在範圍中。val 的使用(出現在 val 的聲明之前)是正確的:
將該引用綁定到 Inner2 類中的資料成員。同樣,Inner2::process 成員函數體中對 Outer 類的 handle 的使用也正確,當編譯 Inner2 類的成員的時候,整個 Outer 類在範圍中。
C++嵌套類