9 类
1. 类是一种类型。在它的作用域内,该类型的名字称为类名。
类名:
标识符
模板 id
Class-specifiers 和 elaborated-type-specifier s 用来描述类名。类的对象是由一系列(可能为空)的成员和基类对象。
class-specifier: (类描述器)
class-head { member-specificationopt }
class-head:
class-key identifieropt base-clauseopt
class-key nested-name-specifier identifier base-clauseopt
class-key nested-name-specifieropt template-id base-clauseopt
class-key:
class
struct
union
2. 在类名可见之后,该类就被插入到了声明它的域中。类名也插入到它本身的作用域中;这就是所谓的“注入类名”。为了进行权限检查,注入类名被当做像个公有成员名字一样。类描述器通常被用来定义类。当类描述器中闭合的花括号可见时,类就被认为定义了,即便它的成员尚未定义。
3. 完整的类的对象和成员子对象的大小不能为零。【注:类对象可以被赋值、作为参数传给函数、被函数返回(除了拷贝对象被限制的情况)。用户可以定义其他抽象操作符,比如比较大小操作符。】
4. 结构是用关键字 struct 定义的类;它的成员和基类默认是公开的。联合是用关键字 union 定义的类;它的成员和基类默认是公开的,每次只能存放一个数据成员。平凡结构是个没有静态数据成员(包括非平凡结构、非平凡联合、及其数组、引用)、没有自定义的拷贝赋值操作符、没有自定义的析构函数的聚集类。平凡类或者是平凡结构,或者是平凡联合。
9.1 类名
1. 类的定义引入一种新类型。【例如:
struct X { int a; };
struct Y { int a; };
X a1;
Y a2;
int a3;
声明了三种不同类型的变量。这意味着:
a1 = a2; // 错误 : Y 赋值给 X
a1 = a3; // 错误 : int 赋值给 X
是类型不匹配,
int f(X);
int f(Y);
是函数 f 的重载而不是 2 次声明统一个函数 f 。同理,
struct S { int a; };
struct S { int a; }; // 错误 , 两次定义
是非法的,因为定义了 2 次 S 。】
2. 类定义将类名引入定义它的作用域,隐藏了在域中同名的类、对象、函数或其他声明。如果类定义的域中有个同名的对象、函数或枚举器,当这两个声明同时出现在作用域中时,类只能通过详细类型描述符来引用。【例:
struct stat {
// ...
};
stat gstat; // use plain stat to
// define variable
int stat(struct stat*); // redeclare stat as function
void f()
{
struct stat* ps; // struct prefix needed
// to name struct stat
// ...
stat(ps); //call stat()
// ...
}
】
仅包含“类关键字 标识符”这种形式的声明,或者是个重复声明,或者是个前向声明。这将类名引入域中。【例:
struct s { int a; };
void g()
{
struct s; // hide global struct s
// with a local declaration
s* p; // refer to local struct s
struct s { char* p; }; // define local struct s
struct s; // redeclaration, has no effect
}
】【注:这种声明允许互相引用的类定义。【例:
class Vector;
class Matrix {
// ...
friend Vector operator*(Matrix&, Vector&);
};
class Vector {
// ...
friend Vector operator*(Matrix&, Vector&);
};
】】
3. 详细类型说明符也可以用作声明的一部分的类描述符。与类声明不同的是,如果该详细描述的类在作用域中,那么这个详细描述的类名指的就是它。【例:
struct s { int a; };
void g(int s)
{
struct s* p = new struct s; // global s
p->a = s; // local s
}
4. 【注:类名的声明在该标识符在类定义或详细类型描述符中可见的时候就立即生效。例如, class A * A;
首先将 A 指定为类的名字,然后将其重定义为指向该类的一个指针。这意味着,要想引用类 A 就必须使用它的详细描述形式。这种命名的艺术性很容易造成混乱,应该尽量避免。】
5. 命名类的 typedef-name 是个类名,但不应该使用详细描述形式。