特殊工具与技术

--嵌套类

能够在还有一个类内部(与后面所讲述的局部类不同,嵌套类是在类内部)定义一个类,这种类是嵌套类,也称为嵌套类型。嵌套类最经常使用于定义运行类.

嵌套类是独立的类,基本上与它们的外围类不相关,因此,外围类和嵌套类的对象是互相独立的。嵌套类型的对象不具备外围类所定义的成员,相同,外围类的成员也不具备嵌套类所定义的成员。

嵌套类的名字在其外围类的作用域中可见,但在其它类作用域或定义外围类的作用域中不可见。嵌套类的名字将不会与还有一作用域中声明的名字冲突

嵌套类能够具有与非嵌套类相同种类的成员。像不论什么其它类一样,嵌套类使用訪问标号控制对自己成员的訪问。成员能够声明为 public、private 或 protected。外围类对嵌套类的成员没有特殊訪问权,并且嵌套类对其外围类的成员也没有特殊訪问权。

嵌套类定义了其外围类中的一个类型成员。像不论什么其它成员一样,外围类决定对这个类型的訪问。

嵌套类的实现

[实例]

将 QueueItem 类设为 Queue 类的 private 成员,那样,Queue 类(及其友元)能够使用 QueueItem,但 QueueItem 类类型对普通用户代码不可见。一旦 QueueItem 类本身为 private,我们就能够使其成员为 public 成员--仅仅有 Queue 或 Queue 的友元能够訪问 QueueItem 类型,所以不必防止一般程序訪问 QueueItem 成员。通过用保留字 struct 定义 QueueItem 使成员为 public 成员。

新的设计例如以下:

template <typename Type>
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 <class Type>
Queue<Type>::QueueItem::QueueItem(const Type &t):
item(t),next(0) {}

由于Queue和QueueItem是模板,因此该构造函数也为模板.

3.在外围类外部定义嵌套类

嵌套类通常支持外围类的实现细节。我们可能希望防止外围类的用户看见嵌套类的实现代码。

比如,我们可能希望将 QueueItem 类的定义放在它自己的文件里,我们能够在 Queue 类及其成员的实现文件里包括这个文件。正如能够在类定义体外部定义嵌套类的成员一样,我们也能够在外围类定义体的外部定义整个嵌套类:

template <typename Type>
class Queue
{
public:
//... private:
struct QueueItem; QueueItem *head;
QueueItem *tail;
}; template <class Type>
struct Queue<Type>::QueueItem
{
QueueItem(const Type &t):item(t),next(0) {} Type item;
QueueItem *next;
};

注意,我们必须在Queue类体内部声明QueueItem类.

[小心]

在看到在类定义体外部定义的嵌套类的实际定义之前,该类是不全然类型,应用全部使用不全然类型的常规限制。

4.嵌套类静态成员定义

假设QueueItem类声明了一个静态成员,它的定义也须要放在外层作用域中,假定QueueItem有一个静态成员:

template <class Type>
int Queue<Type>::QueueItem::static_mem = 1024;

5.使用外围类的成员

外围作用域的对象与其嵌套类型的对象之间没有联系

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

Queue 类型的对象没有名为 item 或 next 成员。Queue 类的函数成员能够使用 head 和 tail 成员(它们是指向 QueueItem 对象的指针)来获取那些QueueItem 成员。

6.使用静态成员或其它类型的成员

嵌套类能够直接引用外围类的静态成员,类型名和枚举成员[同后面所讲的局部类].然而,引用外围类作用域之外的类型名或静态成员,须要作用域确定操作符.

7.嵌套模板的实例化

实例化外围类模板的时候,不会自己主动实例化类模板的嵌套类。像不论什么成员函数一样,仅仅有当在须要完整类类型的情况下使用嵌套类本身的时候,才会实例化嵌套类。比如,像

Queue<int> qi; 

这种定义,用 int 类型实例化了 Queue 模板,但没有实例化QueueItem<int> 类型。成员 head 和 tail 是指向 QueueItem<int> 指针,这里不须要实例化 QueueItem<int> 来定义那个类的指针。

仅仅有在使用 QueueItem<int> 的时候--仅仅有当 Queue<int> 类的成员函数中对 head 和 tail 解引用的时候,才实例化 QueueItem<int> 类。

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

当处理类成员声明的时候,所用的名字必须在使用之前出现;当处理定义的时候,整个嵌套类和外围类均在作用域中.

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);
}

C++ Primer 学习笔记_104_特殊工具与技术 --嵌套类的更多相关文章

  1. C++ Primer学习笔记(三) C++中函数是一种类型!!!

    C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! (---20160618最新消息,函数名不是变量名...囧) (---201 ...

  2. C++ Primer学习笔记(二)

    题外话:一工作起来就没有大段的时间学习了,如何充分利用碎片时间是个好问题. 接  C++ Primer学习笔记(一)   27.与 vector 类型相比,数组的显著缺陷在于:数组的长度是固定的,无法 ...

  3. Android:日常学习笔记(9)———探究持久化技术

    Android:日常学习笔记(9)———探究持久化技术 引入持久化技术 什么是持久化技术 持久化技术就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失 ...

  4. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  5. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936本文章博客地址:http://blog.csdn.net/qq21497936/article/details/78516 ...

  6. Duilib学习笔记《06》— 窗体基类WindowImpBase

    在前面的例子中我们发现,窗口都是继承CWindowWnd.INotifyUI,然后重载相关函数去实现.显然,我们发现窗口的创建流程实际上都是差不多的,主要只是在OnCreate加载的配置文件不同等等… ...

  7. cocos2d-x实战 C++卷 学习笔记--第4章 字符串 __String类

    前言: <cocos2d-x实战C++卷>学习笔记.(cocos2d-x 是3.0版本) 介绍 cocos2d-x 通用的字符串类  __String . 使用cocos2d::__Str ...

  8. Python学习笔记(十五):类基础

    以Mark Lutz著的<Python学习手册>为教程,每天花1个小时左右时间学习,争取两周完成. --- 写在前面的话 2013-7-24 23:59 学习笔记 1,Python中的大多 ...

  9. mybatis学习笔记(二)-- 使用mybatisUtil工具类体验基于xml和注解实现

    项目结构  基础入门可参考:mybatis学习笔记(一)-- 简单入门(附测试Demo详细过程) 开始体验 1.新建项目,新建类MybatisUtil.java,路径:src/util/Mybatis ...

随机推荐

  1. 根据PID获取进程名&根据进程名获取PID

    Liunx中 通过进程名查找进程PID可以通过 pidof [进程名] 来查找.反过来 ,相同通过PID查找进程名则没有相关命令.在linux根目录中,有一个/proc的VFS(虚拟文件系统),系统当 ...

  2. POJ 1751 Highways (ZOJ 2048 ) MST

    http://poj.org/problem?id=1751 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2048 题目大 ...

  3. window下利用navicat访问Linux下的mariadb数据库

    1.再Linux上成功安装mariadb数据库后,不管是在dos(敲命令mysql -h192.168.136.8 -uroot -p)下或者是navicat(创建连接)下连接mariadb数据库,会 ...

  4. [Angular] NgRx/effect, why to use it?

    See the current implementaion of code, we have a smart component, and inside the smart component we ...

  5. C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结。

    C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结. 一.总结 C++/Php/Python/Shell 程序按行读取文件或者控制台(php读取标准输入:$fp = fope ...

  6. 如何将服务器传来的字符串转成HTML显示在前端页面

    从后台返回的字符串是一段HTML源代码,如果不做处理,直接插入前端页面中 ,会显示为字符: 现需求为:将后台返回的字符串str以HTML显示在div中: <div id='container'& ...

  7. Java中的浮点数-科学计数法-加减乘除

    上次,提到"元转分"这个浮点数问题,boss倾向于手动把1.23元这种格式,转换成123分.    但实际上,浮点数很容易遇到精度问题.    比如,System.out.prin ...

  8. 【codeforces 750A】New Year and Hurry

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  9. js如何遍历表单所有控件

    js如何遍历表单所有控件 一.总结 一句话总结: 1.获取form表单里面的的所有元素:通过formelement.elements,这里form元素通过name属性直接定位 var fele=for ...

  10. springMVC出现HTTP Status 405 - Request method 'GET' not supported错误的解决方法

    今天在写一个简单的springMVC的表单请求处理时,出现了这个问题.我的form表单用的是post方法提交,并没有使用get方法,出现这个问题时,笔者可谓是一脸懵逼. 这是form表单: 这是对po ...