热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++day31友元(二)嵌套类

文章目录嵌套类(新增):在其它类中声明的类为什么要设计嵌套类,有什么用?(成全其包含类)从类中定义结构体引入作

文章目录

  • 嵌套类(新增):==在其它类中声明==的类
    • 为什么要设计嵌套类,有什么用?(成全其包含类)
    • 从类中定义结构体引入
    • 作用域和访问控制
      • 嵌套类的作用域是包含它的类
      • 访问控制规则
    • 示例:用模板类实现队列
  • 总结


嵌套类(新增):在其它类中声明的类

nested class

在一个类的内部定义另一个类,前者叫做包含类,后者叫做嵌套类。以前C++不支持嵌套类,是新增的(不确定是不是C++11增的。)。

包含和嵌套类可不同哈。包含是说:把一个类的对象作为另一个类的成员。而嵌套类不是说什么对象,而是创建了一个新的类!只不过这个类只在它的包含类中有效,外部要用也不是不可能,后面会讲访问控制。


为什么要设计嵌套类,有什么用?(成全其包含类)

其实设计嵌套类,主要是为了成全包含类,即是为了辅助包含类的实现。后面一点点就会明白。

  • 包含类的成员函数可以创建和使用嵌套类的对象,不需要加类名限定符。

从类中定义结构体引入

其实嵌套类的形式我们早就见过了,那就是在类中声明结构体的时候,这是一种变相的嵌套类,因为结构体是一种成员默认为公有public的类

比如,队列类,这种容器类,需要一个用结构体表示的结点,一般我们都是用的结构体,其实这就是一种嵌套类。栈,链表的实现也是一样。

class Queue
{
private:struct Node{Item item; struct Node * next;};···
};

但是这种嵌套类,并没有真正利用类的功能,即利用类的构造函数去操作。比如吧元素加入到队列中的EnQueue操作:

bool Queue::EnQueue(const Item & item)
{if (isfull())return false;Node * add = new Node;//如果new失败,new会抛出std::bad_alloc异常add->item = item;add->next = NULL;//使用NULL的前提是包含了定义NULL的头文件,不然可以直接用0,或者C++11新增的nullptr···
}

使用NULL的前提是包含了定义NULL的头文件,不然可以直接用0,或者C++11新增的nullptr

可以看到,Node结构体的成员是可以直接被外部赋值的,这就是因为结构体的成员默认是公有的。但是,给成员赋值这种事情,其实应该是构造函数来做才最合适,至少对于真的类来说是这样的。所以我们把Node结构体改为类,并给他写显式的构造函数:

class Queue
{//由于类的默认权限是私有,所以这时候嵌套类Node是Queue类私有的class Node{public:Item item; struct Node * next;Node(const Item & i):item(i), next(0){}};···
};

这时候EnQueue函数就可以改为:

bool Queue::EnQueue(const Item & item)
{if (isfull())return false;Node * add = new Node(item);//用构造函数进行自动初始化,代码更简短也更安全//上面那种情况如果程序员忘记给某一个成员比如next赋值,就很危险···
}

从这个代码也可以看到,Queue类(包含类)的成员函数可以创建和使用嵌套类的对象,不需要加类名限定符。

如果Node类的构造函数的定义不写在Queue类的Node类内部,而是写在单独的方法文件,那就需要加两重类名限定符,以说明Node类是在Queue类中定义的。

Queue::Node::Node(const Item & i):item(i), next(0){}

作用域和访问控制


嵌套类的作用域是包含它的类

所以在包含类外部使用,必须要用类名限定符。

不在作用域内使用,就要用类名限定符。

嵌套类的作用域和可见性是由它被声明的位置决定的,具体来说可以分为:

  • 当嵌套类定义在包含类的public部分时,可以在包含类的外部通过两层类名限定符来使用嵌套类;包含类的派生类当然也可以继承嵌套类。
  • 而定义在私有部分或者保护部分,包含类的外部就根本看不到嵌套类的存在,也没法使用;
  • 如果定义在私有部分,则包含类的派生类也无法得知嵌套类的存在,也无法继承到;只有包含类的对象可以使用嵌套类的对象以及指向嵌套类对象的指针和引用,别人都用不了。(爸爸金屋藏娇的小三的财产怎么可能被原配的孩子继承呢)。

派生类不可以访问类的私有部分。


  • 如果定义在保护部分,则包含类的派生类可以继承到嵌套类。派生类可以创建父类中的嵌套类的对象。

其实嵌套结构和嵌套枚举的作用域也是这样,是包含他们的外层的结构和枚举。
在这里插入图片描述

访问控制规则

要注意,嵌套类这种形式,并没有让包含类对嵌套类的访问有什么特权,也没有让嵌套类对包含类的访问有什么特权。包含类仍然只可以访问到嵌套类的公有成员。

所以一般包含类会把自己的嵌套类设置为私有成员,然后嵌套类的所有成员都是公有的,这样嵌套类就可以完全为包含类所用。

示例:用模板类实现队列

//queuetp.h -- 队列类的模板实现,使用嵌套类
#ifndef _QUEUETP_H_
#define _QUEUETP_H_template<class Item>//通用类型以Item表示
class QueueTp
{class Node{public:Item item;Node * next;Node(Item it &#61; 0, Node * ne &#61; 0):item(it), next(ne){}};enum {Q_SIZE &#61; 10};//里面不需要写分号&#xff01;Node * front;Node * rear;int items;//链表中当前元素数目const int qsize;//队列最大元素数目QueueTp(const QueueTp & q):qsize(0){}//私有构造函数&#xff01;长见识了QueueTp & operator&#61;(const QueueTp & q){return *this;}//重载赋值运算符public:QueueTp(int qs &#61; Q_SIZE);~QueueTp();bool isempty() const {return items&#61;&#61;0;}bool isfull() const {return items&#61;&#61;qsize;}int queuecount() const {return items;}bool enqueue(const Item & item);bool dequeue(Item & item);
};
//QueueTp methods
template<class Item>
QueueTp<Item>::QueueTp(int qs):qsize(qs)//写方法定义时不要写默认参数
{front &#61; rear &#61; 0;//队首和队尾初始化为空指针items &#61; 0;
}template<class Item>
QueueTp<Item>::~QueueTp()
{Node * node;while (front){node &#61; front;front &#61; front->next;delete node;}
}template<class Item>
bool QueueTp::enqueue(const Item & item)
{if (isfull())return false;Node * add &#61; new Node(item);//new失败会抛出异常&#43;&#43;items;if (!front)front &#61; add;elserear->next &#61; add;rear &#61; add;return true;
}template<class Item>
bool QueueTp::dequeue(Item & item)
{if (isempty())return false;item &#61; front->item;Node * node &#61; front;front &#61; front->next;delete node;--items;if (items&#61;&#61;0)rear &#61; 0;return true;
}
#endif

由于Node类里面的item是Item类型的&#xff0c;即通用类型。
所以如果你用char代替Item&#xff0c;那么Node类实际上就是QueueTp::Node类&#xff1b;
如果用int代替Item,则Node类实际是QueueTp::Node类。
这两个Node类是在两个独立的QueueTp类中定义的&#xff0c;完全不会有名称冲突。

测试程序

//main.cpp
#include
#include
#include "queuetp.h"int main()
{using std::cout;using std::cin;using std::string;QueueTp<string> cs(5);//队列size是5string temp;while (!cs.isfull()){cout << "Please enter your name. ""You will be served in the order of ""arrival.\nname: ";getline(cin, temp);cs.enqueue(temp);}cout << "The queue is full. Processing begins!\n";while (!cs.isempty()){cs.dequeue(temp);cout << "Now processing " << temp << "···\n";//这是中文的点&#xff0c;导致输出乱码了&#xff0c;ascii不认识&#xff0c;不知道为啥输出了“路”}return 0;
}

输出

Please enter your name. You will be served in the order of arrival.
name: mm
Please enter your name. You will be served in the order of arrival.
name: ss
Please enter your name. You will be served in the order of arrival.
name: huhu
Please enter your name. You will be served in the order of arrival.
name: lala
Please enter your name. You will be served in the order of arrival.
name: yoyo
The queue is full. Processing begins!
Now processing mm路路路
Now processing ss路路路
Now processing huhu路路路
Now processing lala路路路
Now processing yoyo路路路

要输入英文的省略号点&#xff0c;哈哈哈

Please enter your name. You will be served in the order of arrival.
name: yaya
Please enter your name. You will be served in the order of arrival.
name: huhu
Please enter your name. You will be served in the order of arrival.
name: lala
Please enter your name. You will be served in the order of arrival.
name: hula
Please enter your name. You will be served in the order of arrival.
name: yeye
The queue is full. Processing begins!
Now processing yaya&#96;&#96;&#96;
Now processing huhu&#96;&#96;&#96;
Now processing lala&#96;&#96;&#96;
Now processing hula&#96;&#96;&#96;
Now processing yeye&#96;&#96;

总结

  • 总之嵌套类是定义在别的类内部&#xff0c;然后一般只为这个包含类所用
  • 嵌套类主要是为了辅助设计包含类&#xff0c;它是为了包含类的实现做贡献的&#xff0c;如果不在public部分声明&#xff0c;则它不就不是公有接口的一部分&#xff0c;只为包含类服务。

推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
author-avatar
雪中磐石
人生只有走出来的美丽,没有等出来的辉煌。
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有