C++_类入门3-嵌套类
可以将类B声明在另一个类中。在另一个类A中声明的类B被称为嵌套类(nested class)。
类A的成员函数可以创建和使用嵌套类B的对象。
当且仅当声明为公有部分时,才能在类A的外面使用嵌套类。而且必须使用作用域解析运算符。(旧版C++不支持嵌套类概念)
对类进行嵌套和包含并不同。包含意味着将类C对象作为类A的成员。而对类B进行嵌套不创建类成员,而是定义了一种类型,该类型仅仅在包含嵌套类声明的类A中有效。
对类进行嵌套通常是为了帮助实现另一个类,并避免名称冲突。
class Queue
{
private:
//classs scope definitions
//Node is a nested structure definition local to this class
struct node {Item item; struct Node * next;};
}
结构是其成员在默认情况下公有的类。结构可以理解成一种特殊的类。
所以Node实际上可以看成嵌套类。但该定义没有充分利用类的功能。
具体来说,它没有显式构造函数。接下来进行补救。
Queue的方法enqueue创建了Node:
bool Queue::enqueue(const Item & item)
{
if(isfull())
return false;
Node * add = new Node; //create node
//on failure,new throws std::bad_alloc exception
add->item =item; //set node pointer
add->next =NULL;
...
}
上述代码创建Node后,显式地给Node成员赋值,这种工作更适合由构造函数来完成。
于是可以改写Node如下:
class Queue
{
//Node is a nested calss definition local to this class
class Node
{
public:
Item item;
Node * next;
Node(const Item & i):item(i),next() { }
};
...
}
该构造函数节点的item成员被初始化为i,并将next指针置为0,这是C++编写空值指针的方法之一。
接下来,需要使用构造函数重新编写enqueue():
bool Queue::enqueue(const Item & item)
{
if(isfull())
reutrn false;
Node * add = new Node(item); //create, initialize node
//on failure,new throws std::bad_alloc exception
...
}
这使得enqueue()的代码更短,也更安全,因为它自动进行初始化,无需程序员记住应该做什么。
这个例子在类声明中定义了构造函数。假设想在方法文件中定义构造函数,则定义必须指出Node类,
这是通过两次作用域运算符来完成的;
Queue::Node::Node(const Item & i):item(i),next(0) { }
嵌套类和访问权限
嵌套类的声明位置决定了嵌套类的作用域。即它决定了程序的那些部分可以创建这种类的对象。
其次,和其他类一样,嵌套类的公有部分、保护部分、私有部分控制了对类成员的访问。
在哪些地方可以使用嵌套类以及如何使用嵌套类,取决于作用域和访问控制。
1、作用域
如果嵌套类是在类的私有部分声明的:
则只有类的私有部分知道它,在前一个例子中,被嵌套在Queue声明中的Node类就属于这种情况。
Queue成员可以使用Node对象和Node对象的指针,但是程序的其他部分甚至不知道存在Node类。
而对于从Queue派生而来的类,Node也是不可见的。因为派生类不能直接访问积累的私有部分。
如果嵌套类是在类的保护部分声明的:
则该嵌套类对于后面这个类是可见的,但是对于外部世界则是不可见的。
在这种情况下,派生类知道嵌套类,病可以直接创建这种类型的对象。
如果嵌套类是在类的公有部分声明的:
则后者、后者的派生类以及外部世界使用它,因为它是公有的。
然而,由于嵌套类的作用域为包含它的类,因此在外部世界使用它时,必须使用类限定符。
嵌套结构和枚举的作用域如此相同。其实,很多程序员都使用公有枚举来提供可供客户程序员使用的类常数。
作用域就是指这个对象(类、枚举)可见的范围,有效的范围。
2、访问控制
类可见之后,起决定作用的就是访问控制。
类声明的位置决定了类的作用域或可见性。类可见后,访问控制规则(公有、保护、私有、友元)将决定程序对嵌套类成员的访问权限。
在Queue类声明中声明Node并没有赋予Queue类对Node类的访问特权。
因此Queue类对象只能显式地访问Node对象的公有成员。
由于这个原因,在Queue示例中,Node类的所有成员都被声明为公有的。
这样有悖于应将数据成员声明为私有的惯例,但Node类是Queue类内部实现的一项特性,对外部实际不可见,这是因为Queue类是在Queue类的私有部分声明的。
所以,虽然Queue的方法可以直接访问Node成员,但使用Queue类的客户不能这样做。
模板中的嵌套
模板很适合用于诸如实现Queue等容器类。
将Queue类定义转换为模板时,是否会由于它包含嵌套类而带来问题?答案是不会。
//queuetp.h -- queue template with a nested class
#ifndef QUEUETP_H_
#define QUEUETP_H_ template <class Item>
class QueueTP
{
private:
enum {Q_SIZE =};
//Node is a nested class definition
class Node
{
public:
Item item;
Node * next;
Node(const Item & i): item(i),next() {}
};
Node * front;
Node * rear;
int item; //current number of items in Queue;
const int qsize; //maximum number of items in Queue;
QueueTP(const QueueTP & q): qsize() {}
QueueTP & operator=(const QueueTP & q) {return *this;}
public:
QueueTP(int qs= Q_SIZE);
~QueueTP();
bool isempty() const{
return item==;
};
bool isfull() const{
return item==qsize;
};
int queuecount const{
return item;
};
bool enqueue(const Item & item); //add item to end
bool dequeue(Item & item); //remove item from front
}; #endif
//QueueTP methods
QueueTP<Item>::QueueTP(int qs): qsize(qs)
{
front = reart = ;
items = ;
} template <class Item>
QueueTP<Item>::~QueueTP()
{
Node * temp;
while()
{
temp=front;
front=front->next;
delete temp;
}
} template <class Item>
bool QueueTP<Item>::enqueue(const Item & item)
{
if(isfull())
return false;
Node * add = new Node(item); //create node
//on failure, new throws std::bad_alloc exception
items++;
if(front ==)
front == add;
else
rear->next == add;
rear = add;
return true;
} template <class Item>
bool QueueTP<Item>::dequeue(Item & item)
{
if(front == )
return false;
item = front->item;
items--;
Node * temp =front;
front = front->next;
delete temp;
if(items==)
rear = ;
return true;
}
在模板中Node是利用Item类型来定义的。
下面声明将导致Node被定义成用于储存double值:
QueueTP<double> dq;
而下面的声明将导致Node被定义成用于存储char的值:
QueueTP<char> dq;
这两个Node类将在两个独立的QueueTP类中定义,因此不会发生名称冲突。
即一个节点的类型为QueueTP<double>::Node
另一个节点的类型为QueueTP<char>::Node
接下来用一个小程序测试一下:
//nested.cpp -- using a queue that has a nested class #include <iostream>
#include <string>
#include "queuetp.h" int main()
{
using std::string;
using std::cin;
using std::cout; QueueTP<string> cs();
string temp; while(!cs.isfull())
{
cout<<"Please enter your name.Your will be"
"served in the order of arrival.\n"
"name:";
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";
}
return ;
}
C++_类入门3-嵌套类的更多相关文章
- Java基础 -- 嵌套类(非静态嵌套类、静态嵌套类)
可以将一个类的定义放在另一个类的内部定义,这样的类就被称为嵌套类,包含嵌套类的类被称为外部类(outer class),也可以叫做封闭类. 嵌套类可以分为两种: 静态嵌套类(Static Nested ...
- JAVA嵌套类:静态嵌套类和非静态嵌套类
1.内部类定义 内部类在维基百科的定义为: 面向对象编程中,内部类(又叫做嵌套类)是在另一个类或者接口中进行声明的类.内部类不同于子类(subclass).(译者注:wiki的注解有误,内部类和嵌套 ...
- C++_类入门2-使用类
进一步探讨类的特征,重点是类设计技术,而不是通用原理.一些特性很容易,一些特性很微妙. 运算符重载 目的是使C++操作更美观,更接近于内置类型的操作. 隐藏了内部的实现机理,并强调了实质. 格式:op ...
- scala 学习笔记(04) OOP(上)主从构造器/私有属性/伴生对象(单例静态类)/apply方法/嵌套类
一.主从构造器 java中构造函数没有主.从之分,只有构造器重载,但在scala中,每个类都有一个主构造器,在定义class时,如果啥也没写,默认有一个xxx()的主构造器 class Person ...
- 【转】C#类的分类(静态类、实例类、嵌套类、结构、简单的抽象类、简单的密封类)
静态类 -------------------------------------------------------------------------------- 静态类就是在class关键字前 ...
- C++ Primer 学习笔记_104_特殊工具与技术 --嵌套类
特殊工具与技术 --嵌套类 能够在还有一个类内部(与后面所讲述的局部类不同,嵌套类是在类内部)定义一个类,这种类是嵌套类,也称为嵌套类型.嵌套类最经常使用于定义运行类. 嵌套类是独立的类,基本上与它们 ...
- spring 笔记1: mvn 中Controller方法的参数不能是嵌套类(内部类)。
最近做spring开发,个人认为,Controller和客户端js通讯时传递的参数类 只使用某几个方法,为了减少对其他功能的影响,想把参数类定义为Controller类的 嵌套类(内部类).但是实践发 ...
- JAVA 嵌套类和内部类
一.什么是嵌套类及内部类? 可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型: 静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类, ...
- Java内部类、静态嵌套类、局部内部类、匿名内部类
Nested classes are further divided into two types: static nested classes: If the nested class is sta ...
随机推荐
- Ant之build.xml详解---可用
Ant的概念 :在Eclipse中使用Ant Ant是Java平台下非常棒的批处理命令执行程序,能非常方便地自动完成编译,测试,打包,部署等等一系列任务,大大提高开发效率. Ant和make命令很像. ...
- oracle级联更新与级联删除
Oracle级联删除:可以使用外键约束来实现,建立表的主外键关系,给列设置级联删除.如下: ——创建了CLASS表,并设置ID字段为主键. -- Create tablecreate table CL ...
- 使用Layered Window遇到的一些问题及解决方法
1. 使用Layered Window需要设置 WS_EX_LAYERED 属性 2. Layered Window不能作为Child Window 3. 它也不能包含子窗口,为什么呢,因为它收不到 ...
- opennebula 模板参数说明
两种模板配置方式一.光驱引导启动需要配置:disk1:磁盘类型:cdrom 驱动类型:file 磁盘标记:hd 是否只读:yesDisk2:磁盘类型:DATABLOCK驱 ...
- PHP数组的详细解读
数组的定义 数组的本质是管理和操作一组变量,数组中可以存储任意长度的数据,也可以存储任意类型的数据.数组中的单元称为元素,每个元素包括下标(键)和值,访问元素的时候,是通过下标来访问,包括一维数组,二 ...
- 2.一个简单的c++程序。
每个程序员的Hello World程序 //This is a small c++ program #include <iostream> int main() { std::cout & ...
- UVa 11149 Power of Matrix (矩阵快速幂,倍增法或构造矩阵)
题意:求A + A^2 + A^3 + ... + A^m. 析:主要是两种方式,第一种是倍增法,把A + A^2 + A^3 + ... + A^m,拆成两部分,一部分是(E + A^(m/2))( ...
- APUE(3)---文件I/O (1)
一.引言 UNIX系统中的大多数文件对I/O只需用到5个函数:open/read/write/lseek和close,这些函数都是不带缓冲I/O(Unbuffered I/O).只要涉及到多个进程间共 ...
- poj2513 Fence Repair(小根堆)
Description Farmer John wants to repair a small length of the fence around the pasture. He measures ...
- AD对象DirectoryEntry本地开发
DirectoryEntry类如果需要在本地计算机开发需要满足以下条件: 1.本地计算机dns解析必须和AD域控制器的dns保持一致,如图: 2.必须模拟身份验证,才能操作查询AD用户 /// < ...