【C++基础】第一百一十课:[特殊工具与技术]嵌套类

嵌套类

Posted by x-jeff on September 10, 2024

【C++基础】系列博客为参考《C++ Primer中文版(第5版)》C++11标准)一书,自己所做的读书笔记。
本文为原创文章,未经本人允许,禁止转载。转载请注明出处。

1.嵌套类

一个类可以定义在另一个类的内部,前者称为嵌套类(nested class)或嵌套类型(nested type)。

嵌套类是一个独立的类,与外层类基本没什么关系。特别是,外层类的对象和嵌套类的对象是相互独立的。在嵌套类的对象中不包含任何外层类定义的成员;类似的,在外层类的对象中也不包含任何嵌套类定义的成员。

嵌套类的名字在外层类作用域中是可见的,在外层类作用域之外不可见。和其他嵌套的名字一样,嵌套类的名字不会和别的作用域中的同一个名字冲突。

嵌套类中成员的种类与非嵌套类是一样的。和其他类类似,嵌套类也使用访问限定符来控制外界对其成员的访问权限。外层类对嵌套类的成员没有特殊的访问权限,同样,嵌套类对外层类的成员也没有特殊的访问权限。

嵌套类在其外层类中定义了一个类型成员。和其他成员类似,该类型的访问权限由外层类决定。位于外层类public部分的嵌套类实际上定义了一种可以随处访问的类型;位于外层类protected部分的嵌套类定义的类型只能被外层类及其友元和派生类访问;位于外层类private部分的嵌套类定义的类型只能被外层类的成员和友元访问。

1.1.声明一个嵌套类

1
2
3
4
5
class TextQuery {
public:
    class QueryResult; //嵌套类稍后定义
    //...
}

1.2.在外层类之外定义一个嵌套类

我们在TextQuery内声明了QueryResult,但是没有给出它的定义。和成员函数一样,嵌套类必须声明在类的内部,但是可以定义在类的内部或者外部。

当我们在外层类之外定义一个嵌套类时,必须以外层类的名字限定嵌套类的名字:

1
2
3
4
5
6
7
8
9
10
//QueryResult是TextQuery的成员,下面的代码负责定义QueryResult
class TextQuery::QueryResult {
    //位于类的作用域内,因此我们不必对QueryResult形参进行限定
    friend std::ostream& print(std::ostream&, const QueryResult&);
public:
    //无须定义QueryResult::line_no
    //嵌套类可以直接使用外层类的成员,无须对该成员的名字进行限定
    QueryResult(std::string, std::shared_ptr<std::set<line_no>>, std::shared_ptr<std::vector<std::string>>);
    //...
};

和原来的类相比唯一的改动是,我们无须在QueryResult内定义line_no成员了。因为该成员属于TextQuery,所以QueryResult可以直接访问它而不必再定义一次。

在嵌套类在其外层类之外完成真正的定义之前,它都是一个不完全类型

1.3.定义嵌套类的成员

1
2
3
//QueryResult类嵌套在TextQuery类中
//下面的代码为QueryResult类定义名为QueryResult的成员
TextQuery::QueryResult::QueryResult(string s, shared_ptr<set<line_no>> p, shared_ptr<vector<string>> f) : sought(s), lines(p), file(f) { }

1.4.嵌套类的静态成员定义

如果QueryResult声明了一个静态成员,则该成员的定义将位于TextQuery的作用域之外。

1
2
3
//QueryResult类嵌套在TextQuery类中
//下面的代码为QueryResult定义一个静态成员
int TextQuery::QueryResult::static_mem = 1024;

1.5.嵌套类作用域中的名字查找

名字查找的一般规则在嵌套类中同样适用。

如我们所知,嵌套类是其外层类的一个类型成员,因此外层类的成员可以像使用任何其他类型成员一样使用嵌套类的名字。因为QueryResult嵌套在TextQuery中,所以TextQuery的query成员可以直接使用名字QueryResult:

1
2
3
4
5
6
7
8
9
10
11
12
//返回类型必须指明QueryResult是一个嵌套类
TextQuery::QueryResult TextQuery::query(const string &sought) const
{
    //如果我们没有找到sought,则返回set的指针
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    //使用find而非下标以避免向wm中添加单词
    auto loc = wm.find(sought);
    if (loc == wm.end())
        return QueryResult(sought, nodata, file); //没有找到
    else
        return QueryResult(sought, loc->second, file);
}

1.6.嵌套类和外层类是相互独立的

尽管嵌套类定义在其外层类的作用域中,但是外层类的对象和嵌套类的对象没有任何关系。嵌套类的对象只包含嵌套类定义的成员;同样,外层类的对象只包含外层类定义的成员,在外层类对象中不会有任何嵌套类的成员。