程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ Primer 學習筆記_104_特殊工具與技術 --嵌套類

C++ Primer 學習筆記_104_特殊工具與技術 --嵌套類

編輯:C++入門知識

C++ Primer 學習筆記_104_特殊工具與技術 --嵌套類


特殊工具與技術

--嵌套類

可以在另一個類內部(與後面所講述的局部類不同,嵌套類是在類內部)定義一個類,這樣的類是嵌套類,也稱為嵌套類型。嵌套類最常用於定義執行類.

嵌套類是獨立的類,基本上與它們的外圍類不相關,因此,外圍類和嵌套類的對象是互相獨立的。嵌套類型的對象不具備外圍類所定義的成員,同樣,外圍類的成員也不具備嵌套類所定義的成員。

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

嵌套類可以具有與非嵌套類相同種類的成員。像任何其他類一樣,嵌套類使用訪問標號控制對自己成員的訪問。成員可以聲明為 public、private 或 protected。外圍類對嵌套類的成員沒有特殊訪問權,並且嵌套類對其外圍類的成員也沒有特殊訪問權。

嵌套類定義了其外圍類中的一個類型成員。像任何其他成員一樣,外圍類決定對這個類型的訪問。

嵌套類的實現

[實例]

將 QueueItem 類設為 Queue 類的 private 成員,那樣,Queue 類(及其友元)可以使用 QueueItem,但 QueueItem 類類型對普通用戶代碼不可見。一旦 QueueItem 類本身為 private,我們就可以使其成員為 public 成員--只有 Queue 或 Queue 的友元可以訪問 QueueItem 類型,所以不必防止一般程序訪問 QueueItem 成員。通過用保留字 struct 定義 QueueItem 使成員為 public 成員。

新的設計如下:

template 
class Queue
{
public:
    //...

private:
    struct QueueItem
    {
        QueueItem(const Type &);
        Type item;
        QueueItem *next;
    };

    QueueItem *head;
    QueueItem *tail;
};

1.嵌套在類模板內部的類是模板

因為Queue是模板,因此它的成員也是模板,而且QueueItem的模板形參與其外圍類Queue的模板形參相同.

Queue 類的每次實例化用對應於 Type 的適當模板實參產生自己的QueueItem 類。QueueItem 類模板的實例化與外圍 Queue 類模板的實例化之間的映射是一對一的。

2.定義嵌套類的成員

在其類外部定義的嵌套類成員,必須定義在定義外圍類的同一作用域中。在其類外部定義的嵌套類的成員,不能定義在外圍類內部,嵌套類的成員不是外圍類的成員。

QueueItem 類的構造函數不是 Queue 類的成員,因此,不能將它定義在Queue 類定義體中的任何地方.

template 
Queue::QueueItem::QueueItem(const Type &t):
item(t),next(0) {}

因為Queue和QueueItem是模板,因此該構造函數也為模板.

3.在外圍類外部定義嵌套類

嵌套類通常支持外圍類的實現細節。我們可能希望防止外圍類的用戶看見嵌套類的實現代碼。

例如,我們可能希望將 QueueItem 類的定義放在它自己的文件中,我們可以在 Queue 類及其成員的實現文件中包含這個文件。正如可以在類定義體外部定義嵌套類的成員一樣,我們也可以在外圍類定義體的外部定義整個嵌套類:

template 
class Queue
{
public:
    //...

private:
    struct QueueItem;

    QueueItem *head;
    QueueItem *tail;
};

template 
struct Queue::QueueItem
{
    QueueItem(const Type &t):item(t),next(0) {}

    Type item;
    QueueItem *next;
};

注意,我們必須在Queue類體內部聲明QueueItem類.

[小心]

在看到在類定義體外部定義的嵌套類的實際定義之前,該類是不完全類型,應用所有使用不完全類型的常規限制。

4.嵌套類靜態成員定義

如果QueueItem類聲明了一個靜態成員,它的定義也需要放在外層作用域中,假定QueueItem有一個靜態成員:

template 
int Queue::QueueItem::static_mem = 1024;

5.使用外圍類的成員

外圍作用域的對象與其嵌套類型的對象之間沒有聯系

template 
void Queue::pop()
{
    QueueItem *q = head;
    head = head -> next;
    delete q;
}

Queue 類型的對象沒有名為 item 或 next 成員。Queue 類的函數成員可以使用 head 和 tail 成員(它們是指向 QueueItem 對象的指針)來獲取那些QueueItem 成員。

6.使用靜態成員或其他類型的成員

嵌套類可以直接引用外圍類的靜態成員,類型名和枚舉成員[同後面所講的局部類].然而,引用外圍類作用域之外的類型名或靜態成員,需要作用域確定操作符.

7.嵌套模板的實例化

實例化外圍類模板的時候,不會自動實例化類模板的嵌套類。像任何成員函數一樣,只有當在需要完整類類型的情況下使用嵌套類本身的時候,才會實例化嵌套類。例如,像

Queue qi; 


這樣的定義,用 int 類型實例化了 Queue 模板,但沒有實例化QueueItem 類型。成員 head 和 tail 是指向 QueueItem 指針,這裡不需要實例化 QueueItem 來定義那個類的指針。

只有在使用 QueueItem 的時候--只有當 Queue 類的成員函數中對 head 和 tail 解引用的時候,才實例化 QueueItem 類。

嵌套類作用域中的名字查找

當處理類成員聲明的時候,所用的名字必須在使用之前出現;當處理定義的時候,整個嵌套類和外圍類均在作用域中.

class Outer
{
public:
    struct Inner
    {
        void process(const Outer &);    //OK
        Inner2 val;     //Error
    };
    struct Inner2
    {
    public:
        Inner2(int i = 0):val(i) {}

        void process(const Outer &out)  //OK
        {
            out.handle();
        }

    private:
        int val;
    };

    void handle() const;
};

[說明]

編譯器首先處理 Outer 類成員的聲明 Outer::Inner 和 Outer::Inner2。將名字 Outer 作為 Inner::process 形參的使用被綁定到外圍類,在看到process 的聲明時,那個類仍是不完整的,但形參是一個引用,所以這個使用是正確的。

數據成員 Inner::val 的聲明是錯誤的,還沒有看到 Inner2 類型。

Inner2 中的聲明看來沒有問題--它們大多只使用內置類型 int。唯一的例外是成員函數 process,它的形參確定為不完全類型 Outer。因為其形參是一個引用,所以 Outer 為不完全類型是無關緊要的。

直到看到了外圍類中的其余聲明之後,編譯器才處理構造函數和 process 成員的定義。對 Outer 類聲明的完成將函數 handle 的聲明放在作用域中。

當編譯器查找 Inner2 類中的定義所用的名字時,Inner2 類和 Outer 類中的所有名字都在作用域中。val 的使用(出現在 val 的聲明之前)是正確的:將該引用綁定到 Inner2 類中的數據成員[不大理解這一段是什麼意思%>_<%]。同樣,Inner2::process 成員函數體中對 Outer 類的 handle 的使用也正確,當編譯 Inner2 類的成員的時候,整個 Outer 類在作用域中。

使用作用域操作符控制名字查找

可以使用作用域操作符訪問handle的全局版本:

        void process(const Outer &out)
        {
            ::hadle(out);
        }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved