1. 程式人生 > >C++嵌套類

C++嵌套類

emp struct 外部 ember next 基本上 cte error: 派生類

可以在另一個類內部定義一個類,這樣的類是嵌套類,也稱為嵌套類型。嵌套類是獨立的類,基本上與它們的外圍類不相關,外圍類對嵌套類的成員沒有特殊訪問權,並且嵌套類對其外圍類的成員也沒有特殊訪問權。

嵌套類的名字在其外圍類的作用域中可見,但在其他類作用域或定義外圍類的作用域中不可見。嵌套類的名字將不會與另一作用域中聲明的名字沖突。

嵌套類定義了其外圍類中的一個類型成員。像任何其他成員一樣,外圍類決定對這個類型的訪問。在外圍類的 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++嵌套類