一个类可以在另一个类中声明,这个类就称为“嵌套类”(nested class),它通过提供新的类型类作用域来避免名称混乱,而包含嵌套类的类称为“包含类”(enclosing class)。
包含类的成员函数可以创建和使用嵌套类的对象,而仅当声明位于公有部分,才能在包含类的外面使用嵌套类,并且必须使用作用域解析运算符。
下面的例子展示了如何声明嵌套类:
[C++] 纯文本查看 复制代码
// nested_class_declarations.cpp
class BufferedIO
{
public:
enum IOError { None, Access, General };
// 声明嵌套类 BufferedInput.
class BufferedInput
{
public:
int read();
int good()
{
return _inputerror == None;
}
private:
IOError _inputerror;
};
// 声明嵌套类 BufferedOutput.
class BufferedOutput
{
// 成员列表
};
};
int main()
{
}
在上面,BufferedIO::BufferedInput 和 BufferedIO::BufferedOutput 在 BufferedIO 里声明。那么,BufferedInput 和 BufferedOutput 在外部是不可见的,即不能在 main() 函数里直接用它来声明一个对象,比如 BufferedInput myinput; 和 BufferedOutput myoutput; 是错误的。但是,像在上面的代码中,这两个嵌套类位于包含类的共有部分,因此可以用作用域限定符来在 main() 中声明对象,比如:- int main()
- {
- BufferedIO::BufferedInput myinput;
- BufferedIO::BufferedOutput myoutput;
- }
复制代码 然而,如果两个嵌套类位于私有部分,像上面那么做又是不允许的。这实际上和普通的成员的权限关系是一致的:
如果嵌套类是在包含类的私有部分声明的,则只有后者知道它;对于从包含类派生出来的类,嵌套类也是不可见的,因为派生类不能直接访问基类的私有部分。
如果嵌套类是在包含类的保护部分声明的,则对于后者来说是可见的,但是对于外部世界则是不可见的。但是派生类将知道嵌套类,并可以直接创建这种类型的对象。
如果嵌套类是在包含类的公有部分声明的,则允许后者、后者的派生类以及外部世界使用它。由于嵌套类的作用域为包含它的类,因此在外部世界使用它时,必须使用类限定符,如上 main() 函数所示。
嵌套类仅可以直接使用包含类中的类型名,静态成员名,以及枚举量。如上 BufferedIO 这个例子所示,枚举量 IOError可以直接被嵌套类中的成员函数访问。
看一种特殊的情况:当一个嵌套类被前向声明的时候,它可以在包含类的外面可见。考虑下面的代码:
[C++] 纯文本查看 复制代码 class C
{
public:
typedef class U u_t; // 类 U 在类 C 的外部可见(这里类 U 是一种前向声明)
typedef class V {} v_t; // 类 V 在类 C 外不可见,注意 V 后面有一对大括号,表示类 V 已经被定义
};
int main()
{
// 正确,因为有了上面的前向声明,所以这里可以使用
U* pu;
// 错误,类型名只存在于类 C 的作用域中
u_t* pu2; // C2065
// 错误,V 被定义在类 C 中
V* pv; // C2065
// 正确,因为是全限定形式
C::V* pv2;
}
嵌套类中的成员函数
嵌套类中声明的成员函数可以在文件作用域里定义,考虑下面代码:
[C++] 纯文本查看 复制代码 // member_functions_in_nested_classes.cpp
class BufferedIO
{
public:
enum IOError { None, Access, General };
class BufferedInput
{
public:
int read(); // 声明,但没有定义
int good(); // 声明,但没有定义
private:
IOError _inputerror;
};
class BufferedOutput
{
// 成员列表
};
};
// 在文件作用域中定义 read() 和 good()
int BufferedIO::BufferedInput::read()
{
return(1);
}
int BufferedIO::BufferedInput::good()
{
return _inputerror == None;
}
int main()
{
}
在上面的代码中,注意定义函数时使用的是“限定类型名”(qualified-type-name) 语法:- BufferedIO::BufferedInput::read()
复制代码 这意味着,read() 函数是 BufferedIO 类中的 BufferedInput 类的成员。也可以利用 typedef 来缩短该定义:
- typedef BufferedIO::BufferedInput BIO_INPUT;int BIO_INPUT::read()
复制代码 嵌套类与友元函数
在嵌套类中声明的友元函数的作用域仅在嵌套类中,而不能作用于包含类。因此,友元函数并没有什么特殊访问包含类成员或成员函数的权限。如果你想让嵌套类的友元函数(该函数定义在文件作用域中)中使用一个嵌套类中的名称,
那么需要使用限制类型名称。如下代码所示:
[C++] 纯文本查看 复制代码 // friend_functions_and_nested_classes.cpp
#include <string.h>
enum
{
sizeOfMessage = 255
};
char *rgszMessage[sizeOfMessage];
class BufferedIO
{
public:
class BufferedInput
{
public:
friend int GetExtendedErrorStatus();
static char *message;
static int messageSize;
int iMsgNo;
};
};
char *BufferedIO::BufferedInput::message;
int BufferedIO::BufferedInput::messageSize;
//友元函数定义在文件作用域中
int GetExtendedErrorStatus()
{
int iMsgNo = 1;
//使用限定语法
strcpy_s( BufferedIO::BufferedInput::message,
BufferedIO::BufferedInput::messageSize,
rgszMessage[iMsgNo] );
return iMsgNo;
}
int main()
{
}
|