07-嵌套类
15.2 嵌套类
在C++中,可以将类声明放在另一个类中。在另一个类中声明的类被称为嵌套类(nested class),它通过提供新的类型类作用域来避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能在包含类的外面使用嵌套类,而且必须使用作用域解析运算符(然而,旧版本的C++不允许嵌套类或无法完全实现这种概念)。
对类进行嵌套与包含并不同。包含意味着将类对象作为另一个类的成员,而对类进行嵌套不创建类成员,而是定义了一种类型,该类型仅在包含嵌套类声明的类中有效。
对类进行嵌套通常是为了帮助实现另一个类,并避免名称冲突。Queue类示例(第12章的程序清单12.8)嵌套了结构定义,从而实现了一种变相的嵌套类:
class Queue
{
private:
// class scope definitions
// Node is a nested structure definition local to this class
struct Node {Item item; struct Node * next;};
...
};
由于结构是一种其成员在默认情况下为公有的类,所以Node实际上是一个嵌套类,但该定义并没有充分利用类的功能。具体地说,它没有显式构造函数,下面进行补救。
首先,找到Queue示例中创建Node对象的位置。从类声明(程序清单11.10)和方法定义(程序清单12.11)可知,唯一创建了Node对象的地方是enqueue()方法:
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 pointers
add->next = NULL;
...
}
上述代码创建Node后,显式地给Node成员赋值,这种工作更适合由构造函数来完成。
知道应在什么地方以及如何使用构造函数后,便可以提供一个适当的构造函数定义:
class Queue
{
// class scope definitions
// Node is a nested class definition local to this class
class Node
{
public:
Item item;
Node * next;
Node(const Item & i) : item(i), next(0) { }
};
...
};
该构造函数将节点的item成员初始化为i,并将next指针设置为0,这是使用C++编写空值指针的方法之一(使用NULL时,必须包含一个定义NULL的头文件;如果您使用的编译器支持C++11,可使用nullptr)。由于使用Queue类创建的所有节点的next的初始值都被设置为空指针,因此这个类只需要该构造函数。
接下来,需要使用构造函数重新编写enqueue():
bool Queue::enqueue(const Item & item)
{
if (isfull())
return false;
Node * add = new Node(item); // create, initialize node
// on failure, new throws std::bad_alloc exception
...
}
这使得enqueue()的代码更短,也更安全,因为它自动进行初始化,无需程序员记住应做什么。
这个例子在类声明中定义了构造函数。假设想在方法文件中定义构造函数,则定义必须指出Node类是在Queue类中定义的。这是通过使用两次作用域解析运算符来完成的:
Queue::Node::Node(const Item & i) : item(i), next(0) { }