一个类定义在另一个类的内部,前者称为嵌套类(nested class)或嵌套类型(nested type)。嵌套类常用于定义作为实现部分的类。
class TextQuery {
public:
class QueryResult;
};
class TextQuery::QuertResult {
friend std::ostream& print( std::ostream&, const QueryResult&)'
public:
QueryResult(std::string,
std::shared_ptr>,
std::shared_ptr>>);
};
TextQuery::QueryResult::QueryResult(string s,
shared_ptr> p,
shared_ptr>> f) :
sought(s), lines(p), file(f) { }
TextQuery::QueryResult
TextQuery::query(const string &sought) const
{
static shared_ptr> nodata(new set);
auto loc = wm.find(sought);
if(loc == wm.end())
return QueryResult(sought, nodata, file);
else
return QueryResult(sought, loc->second, file);
}
int TextQuery::QueryResult::static_mem = 1024;
嵌套类 是一个独立的类,与外层类基本没什么关系。特别是,外层类的对象和嵌套类的对象是相互独立的。在嵌套类的对象中不包含任何外层类定义的成员。在外层类的对象也不包含任何嵌套类定义的成员。
嵌套类的名字在外层类作用域中是可见的,在外层类作用域之外是不可见的。
C++早起版本规定,在union中不能含有定义了构造构造或者拷贝成员的类类型成员。C++11标准取消了这个限制。不过,如果union的成员类型定义了自己的构造函数和/或拷贝控制成员,则该union的用法会复杂很多。
当union包含的是内置类型的成员时,编译器将按照成员的次序依次合成默认构造函数或拷贝控制成员。但如果union含有类类型的成员,并且该类型自定义了默认构造函数或拷贝控制成员,则编译器将为union合成对应的版本并将其声明为delete。
例如,string类定义了5个拷贝控制成员以及一个默认构造函数。如果union含有string类型的成员,并且没有自定义默认构造函数或某个拷贝控制成员,则编译器将合成缺少的成员并将其声明为delete的。如果在某各类中含有一个union成员,并且该union含有删除的拷贝控制成员,则类与之对应的拷贝控制操作也应该是删除的。
使用类管理union成员
对于union来说,要想构造或销毁类类型的成员必须执行非常复杂的操作,因此我们通常把含有类类型成员的union内嵌到另一个类当中,这个类可以管理并控制与union的类类型成员有关的状态转换。
class Token {
public:
Token() : tok(INT), ival(0) { }
Token(const Token &t) : tok(t.tok) { copyUnion(t); }
Token &operator=(const Token&);
~Token()
{
if( tok == STR)
sval.~string();
}
Token &operator=(const std::string&);
Token &operator=(char);
Token &operator=(int);
Token &operator=(double);
private:
enum {INT, CHAR, DBL, STR} tok; //判别式
union {
char cval;
int ival;
double dval;
std::string sval;
};
void copyUnion(const Token&);
};
管理判别式并销毁string
Token &Token::operator=(int i)
{
if( tok == STR )
sval.~string();
ival = i;
tok = INT;
return *this;
}
Token &Token::operator=(const std::string &s)
{
if( tok == STR )
sval = s;
else
new(&sval) string(s);
tok = STR;
return *this;
}
管理需要拷贝控制的联合成员
void Token::copyUnion(const Token &t)
{
switch(t.tok){
case Token::INT :
ival = t.ival;
break;
case Token::CHAR :
cval = t.cval;
break;
case Token::DBL :
dval = t.dval;
break;
case Token::STR :
new(&sval) string(t.sval);
break;
}
}
Token &Token::operator=(const Token &t)
{
if(tok == STR && t.tok != STR)
sval.~string();
if(tok == STR && t.tok == STR)
sval = t.sval;
else
copyUnion(t);
tok = t.tok;
return *this;
}
类定义在某个函数内部是,我们称其为局部类(local class)。局部类的所有成员(包括函数在内)都必须完整的定义在类的内部。局部类不允许声明静态数据成员。
嵌套的局部类
可以在局部类内部在嵌套一个类。嵌套类的定义可以出现在局部类之外,但必须定义在于局部类相同的作用域中。局部类内的嵌套类也是一个局部类,必须遵循局部类的各种规定:嵌套类的所有成员必须定义在嵌套类的内部