现在的位置: 首页 > 综合 > 正文

嵌套类

2013年09月11日 ⁄ 综合 ⁄ 共 3238字 ⁄ 字号 评论关闭

 

 一个类可以在另一个类中定义这样的类被称为嵌套类nested class 嵌套类是其外
围类的一个成员嵌套类的定义可以出现在其外围类的公有私有或保护区中

 

嵌套类的名字在其外围类域中是可见的但是在其他类域或名字空间中是不可见的这
意味着嵌套类的名字不会与外围域中声明的相同名字冲突例如
class Node { /* ... */ };
class Tree {
public:
// Node 被封装在 Tree 的域中
// 在类域中 Tree::Node 隐藏了 ::Node
class Node {...};
// ok: 被解析为嵌套类: Tree::Node
Node *tree;
};
// Tree::Node 在全局域中不可见
// Node 被解析为全局的 Node 声明
Node *pnode;
class List {
public:
// Node 被封装在 List 的域中

// 在类域 List::Node 中隐藏了 ::Node
class Node {...};
// ok: 解析为: List::Node
Node *list;
};

私有成员是指这样的成员它只能在该类的成员或友元定义中被访问除非外围类被声
明为嵌套类的友元否则它没有权利访问嵌套类的私有成员

嵌套类也没有任
何特权访问其外围类的私有成员如果我们想授权ListItem 允许它访问类List 的私有成员
那么该外围类List 必须把嵌套类ListItem 声明为友元

==================

注意对于成员函数和静态数据成员而言不一定只有嵌套类的公有成员才能在类定
义之外被定义类ListItem 的私有成员也可以被定义在全局域中

 

嵌套类也可以被定义在其外围类之外例如Lisiltem 的定义也可以在全局域中被给出
如下
class List {
public:
// ...
private:
// 这个声明是必需的
class ListItem;
ListItem *list;
ListItem *at_end;
};
// 用外围类名限定修饰嵌套类名
class List::ListItem {
public:
ListItem( int val = 0 );
ListItem *next;
int value;
};

class List {
public:
// ...
private:
// 这个声明是必需的

class ListItem;
ListItem *list;
ListItem at_end; // 错误: 未定义嵌套类 ListItem
};

 

嵌套类不能直接访问其外围类的非静态成员即使这些成员是公有的任何对外围类的
非静态成员的访问都要求通过外围类的指针引用或对象来完成例如
class List {
public:
int init( int );
private:
class ListItem {
public:
ListItem( int val = 0 );
void mf( const List & );
int value;
int memb;
};
};
List::ListItem::ListItem( int val )
{
// List::init() 是类 List 的非静态成员
// 必须通过 List 类型的对象或指针来使用
value = init( val ); // 错误: 非法使用 init
}

 

下面是成员函数mf()通用引用参数引用init() 从这里我们能够知道成员init()是针对
函数实参指定的对象而被调用的
void List::ListItem::mf( const List &il ) {
memb = il.init(); // ok: 通过引用调用 init()
}

 

下面是成员函数mf()通用引用参数引用init() 从这里我们能够知道成员init()是针对
函数实参指定的对象而被调用的
void List::ListItem::mf( const List &il ) {
memb = il.init(); // ok: 通过引用调用 init()
}

===============

但是嵌套类可
以直接访问外围类的静态成员类型名枚举值假定这些成员是公有的类型名是一个
typedef 名字枚举类型名或是一个类名例如
class List {
public:
typedef int (*pFunc)();
enum ListStatus { Good, Empty, Corrupted };
// ...
private:
class ListItem {
public:
void check_status();
ListStatus status; // ok
pFunc action; // ok
// ...
};
// ...
};
pFunc ListStatus 和ListItem 都是外围类List 的域内部的嵌套类型名这三个名字以及
ListStatus 的枚举值都可以被用在ListItem 的域中这些成员可以不加限定修饰地被引用
void List::ListItem::check_status()
{
ListStatus s = status;
switch ( s ) {
case Empty: ...
case Corrupted: ...
case Good: ...
}
}
在ListItem 的域之外以及在外围类List 域之外引用外围类的静态成员类型名和枚举
名都要求域解析操作符例如
List::pFunc myAction; // ok
List::ListStatus stat = List::Empty; // ok
当引用一个枚举值时我们不能写
List::ListStatus::Empty

===========================

class List {
public:
enum ListStatus { Good, Empty, Corrupted };
// ...
private:
class ListItem {
public:
void check_status();
ListStatus status; // ok
// ...
};
ListItem *list;
// ...
};
int list = 0;
void List::ListItem::check_status()
{
int value = list; // 哪个 list?
}
很有可能程序员想让check_status()中的List 引用全局对象
value 和全局对象List 的类型都是int List::list 成员是指针类型在没有显式转换的
情况它不能被赋给value
不允许ListItem 访问其外围类的私有数据成员如List
list 是一个非静态数据成员在ListItem 的成员函数中必须通过对象指针或引用
来访问它
但是尽管有这些原因在成员check_status()中用到的名字List 仍被解析为类List 的数
据成员list 记住如果在联套类ListItem 的域中没有找到该名字则在查找全局域之前下

一个要查找的是其外围类的域外围类List 的成员list 隐藏了全局域中的对象于是产生一
个错误消息因为在check_status()中使用指针list 是无效的
只有在名字解析成功之后编译器才会检查访问许可和类型兼容性如果名字的用法本
身就是错误的则名字解析过程将不会再去查找更适合于该名字用法的声明而是产生一个
错误消息
为了访问全局对象list 必须使用全局域解析操作符
void List::ListItem:: check_status() {
value = ::list; // ok
}
如果成员函数check_status()被定义成位于ListItem 类体中的内联函数则上面所讲到的
最后一步修改会使编译器产生一个错误消息报告说全局域中的list 没有被声明
class List {
public:
// ...
private:
class ListItem {
public:
// 错误: 没有可见的 ::list 声明
void check_status() { int value = ::list; }
// ...
};
ListItem *list;
// ...
};
int list = 0;
全局对象list 是在类List 定义之后被声明的对于在类体中内联定义的成员函数只考
虑在外围类定义之前可见的全局声明如果check_status()的定义出现在List 的定义之后则
编译器考虑在check_status()定义之前可见的全局声明于是找到对象list 的全局声明

抱歉!评论已关闭.