C++嵌套类使⽤(⼀)
转载于:
⼀、嵌套类
在⼀个类的内部定义另⼀个类,我们称之为嵌套类(nested class),或者嵌套类型。之所以引⼊这样⼀个嵌套类,往往是因为外围类需要使⽤嵌套类对象作为底层实现,并且该嵌套类只⽤于外围类的实现,且同时可以对⽤户隐藏该底层实现。
虽然嵌套类在外围类内部定义,但它是⼀个独⽴的类,基本上与外围类不相关。它的成员不属于外围类,同样,外围类的成员也不属于该嵌套类。嵌套类的出现只是告诉外围类有⼀个这样的类型成员供外围类使⽤。并且,外围类对嵌套类成员的访问没有任何特权,嵌套类对外围类成员的访问也同样如此,它们都遵循普通类所具有的标号访问控制。
若不在嵌套类内部定义其成员,则其定义只能写到与外围类相同的作⽤域中,且要⽤外围类进⾏限定,不能把定义写在外围类中。例如,嵌套类的静态成员就是这样的⼀个例⼦。
前⾯说过,之所以使⽤嵌套类的另⼀个原因是达到底层实现隐藏的⽬的。为了实现这种⽬的,我们需要在另⼀个头⽂件中定义该嵌套类,⽽只在外围类中前向声明这个嵌套类即可。当然,在外围类外⾯定义这个
嵌套类时,应该使⽤外围类进⾏限定。使⽤时,只需要在外围类的实现⽂件中包含这个头⽂件即可。
另外,嵌套类可以直接引⽤外围类的静态成员、类型名和枚举成员(假定这些成员是公有的)。类型名是⼀个typedef名字、枚举类型名、或是⼀个类名。
实例如下:
#ifndef NESTCLASS_H_
#define NESTCLASS_H_
class A
{
public:
A();
~A();
void operate();
private:
class B;
B* m_b;
};
#endif
#include "nestclass.h"
#include <iostream>
using namespace std;
class A::B
{
public:
B(){}
~B(){}
void operate()
{
cout<<"B operate!"<<endl;
}
};
A::A()
{
}
A::~A()
{
}
void A::operate()
{
m_b = new B;
cout<<"A operate!"<<endl;
m_b->operate();
}
#include "nestclass.h"
void main()
{
A a;
a.operate();
}
在嵌套类的定义被看到之前我们只能声明嵌套类的指针和引⽤,如上⾯在A中定义为B m_b⽽不是B* m_b将会引发⼀个编译错误。
关于C++嵌套类的详细⽤法请参考《C++ Primer 第三版》P551。
⼆、局部类
类也可以定义在函数体内这样的类被称为局部类(local class),局部类只在定义它的局部域内可见,与嵌套类不同的是,在定义该类的局部域外没有语法能够引⽤局部类的成员,因此,局部类的成员函数必须被定义在类定义中,在实际中,这就把局部类的成员函数的复杂性限制在⼏⾏代码中,否则,对读者来说,代码将变得很难理解。因为没有语法能够在名字空间域内定义局部类的成员,所以也不允许局部类声明静态数据成员。
在局部类中嵌套的类可以在其类定义之外被定义,但是,该定义必须出现在包含外围局部类定义的局部
域内。在局部域定义中的嵌套类的名字必须由其外围类名限定修饰,在外围类中,该嵌套类的声明不能被省略。例如:
void foo( int val )
{
class Bar {
public:
int barVal;
class nested; // 嵌套类的声明是必需的
};
// 嵌套类定义
class Bar::nested {
// ...
};
}
外围函数没有特权访问局部类的私有成员,当然,这可以通过使外围函数成为局部类的友元来实现。
同嵌套类⼀样,局部类可以访问的外围域中的名字也是有限的,局部类只能访问在外围局部域中定义的类型名、静态变量以及枚举值,例如:
int a, val;
void foo( int val )
{
static int si;
enum Loc { a = 1024, b };
class Bar {
public:
Loc locVal; // ok;
int barVal;
void fooBar( Loc l = a ) { // ok: Loc::adefine的基本用法
barVal = val; // 错误: 局部对象
barVal = ::val; // OK: 全局对象
barVal = si; // ok: 静态局部对象
locVal = b; // ok: 枚举值
}
};
// ...
}
在局部类体内,不包括成员函数定义中的的名字解析过程是,在外围域中查出现在局部类定义之前的声明,在局部类的成员函数体内的名字的解析过程是:在查外围域之前,⾸先直该类的完整域。
还是⼀样,如果先到的声明使该名字的⽤法⽆效,则不考虑其他声明,即使在fooBar() 中使⽤ val 是错的,编译器也不会到全局变量val ,除⾮⽤全局域解析操作符限定修饰 val,如 ::val 。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论