首页 > 编程语言 >C++类基础8——嵌套类

C++类基础8——嵌套类

时间:2024-04-01 12:32:48浏览次数:30  
标签:外层 QueryResult 定义 TextQuery 成员 基础 C++ 嵌套

嵌套类

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

下面是一个使用C++嵌套类的示例:

#include <iostream>

class OuterClass {
public:
    class InnerClass {
    public:
        void printMessage() {
            std::cout << "Hello from InnerClass!" << std::endl;
        }
    };

    void callInnerClass() {
        InnerClass inner;
        inner.printMessage();
    }
};

int main() {
    OuterClass outer;
    outer.callInnerClass();

    return 0;
}

在上面的代码中,OuterClass有一个嵌套类InnerClass。在OuterClasscallInnerClass()函数中,我们创建了InnerClass的一个对象,并调用了它的printMessage()函数。最终的输出结果将会是"Hello from InnerClass!"。

嵌套类常用于定义作为实现部分的类

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

嵌套类的名字在外层类作用域中是可见的,在外层类作用域之外不可见。

和其他嵌套类的名字不会和别的作用域中的同一个名字冲突。

嵌套类中成员的种类与非嵌套类是一样的。

和其他类类似,嵌套类也使用访问限定符的名字一样,来控制外界对其成员的访问权限。

外层类对嵌套类的成员没有特殊的访问权限,同样,嵌套类对外层类的成员也没有特殊的访问权限。

嵌套类在其外层类中定义了一个类型成员。和其他成员类似,该类型的访问权限由外层类决定。

  1. 位于外层类public部分的嵌套类实际上定义了一种可以随处访问的类型;
  2. 位于外层类protected部分的嵌套类定义的类型只能被外层类及其友元和派生类访问:
  3. 位于外层类private部分的嵌套类定义的类型只能被外层类的成员和友元访问。

声明一个嵌套类

我们为TextQuery类定义了一个名为QueryResult的嵌套类,这两个类密切相关。QueryResult类的主要作用是表示TextQuery对象上query操作的结果,显然将QueryResult用作其他目的没有任何意义。为了充分体现这种紧密的相关性,我们可以把QueryResult定义成TextQuery的成员。

class TextQuery {
public: 
class QueryResult; //嵌套类稍后定义
//...
};

我们只需对原来的TextQuery类做一处改动,即将QueryResult声明成嵌套类。

因为QueryResult是一个类型成员,所以我们必须对它先声明后使用,尤其是必须先声明QueryResult,再将它作为query成员的返回类型。类的其他成员没有任何变化。

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

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

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

// 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可以直接访问它而不必再定义一次。


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

定义嵌套类的成员

在这个版本的QueryResult类中,我们并没有在类的内部定义其构造函数。

要想为其定义构造函数,必须指明QueryResult是嵌套在TextQuery的作用域之内的。具体做法是使用外层类的名字限定联套类的名字:

// 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) {}



从右向左阅读函数的名字可知我们定义的是QueryResult类的构造函数,而QueryResult类是嵌套在TextQuery类中的。该构造函数除了把实参值赋给对应的数据成员之外,没有做其他工作。

嵌套类的静态成员定义

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

例如,假设QueryResult有一个静态成员,则该成员的定义将形如:

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

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

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

当然,因为嵌套类本身是一个嵌套作用域,所以还必须查找嵌套类的外层作用域。

这种作用域嵌套的性质正好可以说明为什么我们不在QueryResult的嵌套版本中定义line_no。

原来的QueryResult类定义了该成员,从而使其成员可以避免使用TextQuery::line_no的形式。

然而QueryResult的嵌套类版本本身就是定义在TextQuery中的,所以我们不需要再使用 typedef。嵌套的QueryResult无须说明line_no属于TextQuery就可以直接使用它。

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

//返回类型必须指明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  wn. find(sought);
if (loc =s wm,end())
{
return QueryResult(sought, nodata, file); // 没有找到
else
return QueryResult(sought, loc->second, file);
}


和过去一样,返回类型不在类的作用域中,因此我们必须指明函数的返回TextQuery::QueryResult类型。

不过在函数体内部我们可以直接访问QueryResult,比如上面的return语句就是这样。

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

尽管嵌套类定义在其外层类的作用域中,但是读者必须谨记外层类的对象和嵌套类的对象没有任何关系。

嵌套类的对象只包含嵌套类定义的成员;同样,外层类的对象只包含外层类定义的成员,在外层类对象中不会有任何嵌套类的成员。
说得再具体一些,TextQuery::query的第二条return语句

return QueryResult(sought, loc->second, file);

使用了TextQuery对象的数据成员,而query正是用它们来初始化QueryResult对象的。因为在一个QueryResult对象中不包含其外层类的成员,所以我们必须使用上述成员构造我们返回QueryResult对象。

 

标签:外层,QueryResult,定义,TextQuery,成员,基础,C++,嵌套
From: https://blog.csdn.net/2301_80224556/article/details/137227574

相关文章

  • 【华为OD机试C++】提取不重复的整数
    《最新华为OD机试题目带答案解析》:最新华为OD机试题目带答案解析,语言包括C、C++、Python、Java、JavaScript等。订阅专栏,获取专栏内所有文章阅读权限,持续同步更新!文章目录描述输入描述输出描述示例代码描述输入一个int型整数,按照从右向左的阅读顺序,返回......
  • 系统学习Java:构建坚实的编程基础
    Java是一种广泛使用的编程语言,以其跨平台性、强大的生态系统和稳健的性能而受到开发者的青睐。无论你是编程新手还是希望转战Java的经验丰富的开发者,系统学习Java都需要一个明确的学习路径。本文将为你提供一个全面的指南,帮助你从多个关键方面入手,构建坚实的Java编程基础。......
  • 深入解析Java中的核心数据结构:从基础到进阶实战
    在软件开发领域,熟悉并掌握数据结构对于提升程序性能和优化算法至关重要。本文将全面介绍Java中常用的核心数据结构,辅以示例代码和概念图解,以帮助读者更好地理解和应用这些数据结构。1.数组(Array)数组是Java中最基础的数据结构之一,它是在内存中一块连续区域存放相同类型元......
  • 模拟比赛-14届研究生组C++省赛
    A工作时长题意:若干条打卡记录字符串(年月日时分秒格式),保证打卡记录相邻。求该年工作时长。思路:对字符串处理,转换格式为秒数,排序后相邻相减求和。总结:2月有29天的情况要被4整除,如果能被100整除的话,一定要被400整除。structData{ intmonth;//5 intday;//8 inthour;//......
  • Qt/C++入门基础学习001-绘图基础
    这一节介绍Qt的绘图基础知识,我们都知道,Qt里绘图使用的是QPainter,但是首先需要弄明白:在什么上绘图和在哪里绘图,然后才是怎么绘图,我们就围绕这几个问题来展开。在什么上绘图TheQPaintDeviceclassisthebaseclassofobjectsthatcanbepaintedonwithQPainter.Apa......
  • 高等数学基础篇(数二)之无穷小量阶的比较(补充)
    ......
  • 服务器硬件基础知识202404
    服务器硬件基础知识涵盖了服务器的各个关键组件和它们的功能。具体如下:处理器(CPU):是服务器的大脑,负责执行指令和处理数据。在服务器的成本构成中,CPU及其关联的芯片组通常占据大约50%的比例。内存(RAM):是服务器的临时存储设备,用于存放正在运行的程序和数据。内存的容量直接影响......
  • Linux基础命令篇之——压缩与解压(tar、gzip、bzip2、zip和unzip)
    linux基础命令——解压与压缩以下是关于Linux命令tar、gzip、bzip2、zip和unzip的详细介绍:1.tar这个是Linux用的最多的解压缩命令tar是Linux系统中用于创建和处理归档文件的命令。归档文件是一个包含多个文件和/或目录的单一文件。常与压缩命令gzip或bzip2结合使用,以减......
  • 前端学习<二>CSS基础——15-Sass入门
    Sass简介大家都知道,js中可以自定义变量,css仅仅是一个标记语言,不是编程语言,因此不可以自定义变量、不可以引用等等。面对这些问题,我们现在来引入Sass,简单的说,他是css的升级版,可以自定义变量,可以有if语句,还可以嵌套等等,很神奇吧!那下面我们就来介绍返个神奇的Sass。Sas......
  • 前端学习<二>CSS基础——14-CSS3属性详解:Web字体
    前言开发人员可以为自已的网页指定特殊的字体(将指定字体提前下载到站点中),无需考虑用户电脑上是否安装了此特殊字体。从此,把特殊字体处理成图片的方式便成为了过去。支持程度比较好,甚至IE低版本的浏览器也能支持。字体的常见格式不同浏览器所支持的字体格式是不一样的,我......