class名称被视为一个类型(type)名称,每个class都会提供一组操作函数作用于其object上。class由两部分组成:一组公开的(public)操作函数和运算符,以及一组私有的(private)实现细节。public部分称为class的member function,代表用户可以访问的公开接口。private实现细节可由member function的定义以及与此class相关的任何数据组成。
4.1 如何实现一个Class
以定义stack的存放string元素的non-template版本为例。
- 前置声明
将class名称告诉编译器,别的啥也没给。可以帮助进行类指针的定义,或以此class作为数据类型。
class Stack
Stack *pt=0;
void process(const Stack&);
- 定义
由class的声明和主体组成。主体内的关键字public标示这部分块的“member访问权限”是公开的,在哪都能访问;private member只能在memeber function或者是class friend内被访问。(放在与class同名的头文件Stack.h中)
class Stack {
public:
bool push(const string&);
bool pop(string &elem);
bool peek(string &elem);
bool empty();
bool full();
//size定义于class本身中,其他member仅仅只是声明
int size() { return _stack.size(); }
private:
vector<string> _stack;//作者编码习惯 在data member之前加下划线
};
- member function声明
必须在class主体内声明。
- member function定义
- 如果在class主体内定义,这个member function会自动地视为inline函数(放在与class同名的头文件Stack.h中)
- 如果在class主体外定义,如果希望该函数为inline要在最前面指定关键字inline(放在与class同名的头文件Stack.h中),如果不是inline类型,要使用特殊语法(在程序代码文件中定义,该文件和class同名,后缀cpp)
4.2 什么是构造函数和析构函数
-
构造函数
用来初始化类对象的数据成员的函数称为constructor。Constructor的函数名称必须与class名称相同,构造函数不应指定返回类型,也不用返回任何值,它可以被重载。
- 默认构造函数
不接受任何参数,为每个参数提供了默认值。
- 成员初始化列表
构造函数定义的第二种初始化语法,紧接在参数列表最后的冒号后面,是个以逗号分隔的列表,赋值给member的数值被放在member名称后面的小括号中。
-
析构函数
用来释放在构造函数中或对象生命周期中分配的资源。命名规则:class名称再加‘~’前缀。无返回值,没有任何参数,绝不可能被重载。
- 成员逐一初始化
在默认情形下以某个class object作为另一个object的初值,类数据成员会被依次复制。如果在赋值后对赋值对象使用了析构函数就会使得原对象的析构函数重复释放空间,这种情况需要另行定义copy constructor并在其中编写正确的初始化操作。
4.3 何谓mutable和const
在member function的参数列表之后加const说明这个member function不会更改class object的内容。如果是在class主体以外定义的const member function,必须同时在声明与定义中指定const。
- Mutable Data Member
被标示为mutable的数据成员,改变其值不算改变class object的状态,不算破坏了对象的常量性。
4.4 什么是this指针
- this指针可以指向整个对象,在member function内用来指向其调用者,可以让我们访问其调用者的一切。
- dereference操作:*this可以返回由this指向的对象。
- 想要用一个对象复制出另一个对象,可以先检查两个对象是否相同: this != &rhs
4.5 静态类成员
-
Static Data Member
- 用来表示唯一的、可共享的member。
- 可以在同一类的所有对象中被访问。
- 只有唯一一份实体,因此必须在程序代码文件中提供定义。
- 名称要附上class scope运算符:vector<int> Triangular::elems;
- const static data member可以在声明时即指定初值。
-
Static Member Function
- 只有在“不访问任何non-static member”的条件下member function才能被声明为static。
- 声明方式:声明前加关键字static:static bool is_elem(int);
- 在class主体外定义member function时无须重复加static(此规则同样适用static data member)。
4.6 打造一个Iterator Class
就是对class进行运算符重载操作。
- 为iterator class定义运算符
像定义member function一样,在运算符前加关键字operatpr即可。运算符可以直接作用于其class object。如果希望将运算符作用于指针所指的对象,就要先提领该指针,取出其所指对象。
-
运算符重载规则
- 不可以引入新运算符。
- 运算符的操作数个数不可改变。
- 运算符的优先级不可改变。
- 运算符函数的参数列表中,必须至少有一个参数为class类型。
- non-member运算符
其参数列表中比相应的member运算符多一个参数,也就是this指针。对member运算符而言,这个this指针隐式代表左操作数。
-
嵌套类型(Nested Type)
typedef可以为某个类型设定另一个不同的名称。
typedef existing_type new_name;
4.7 友元
当一个class将其他function或class指定为friend,那friend就具备了与class member function相同的访问权限,可以访问class的private member。通常是为了效率考虑,也可以提供具有public访问权限的inline函数代替。
- 声明方式
在function或者class前加关键字friend。
4.8 实现一个copy assignment operator
用来取代默认成员逐一初始化操作。
4.9 实现一个function object
- function object
是一种“提供有function call运算符”的class。function call运算符可接受任意个数的参数,被用来支持矩阵的多维度下标操作。
将function call运算符应用于对象身上,便可以调用function call运算符。通常会把function object当作参数传给泛型算法。
4.10 重载iostream运算符
为了显示对象的内容,对某个class object进行读取和写入操作。
4.11 指针,指向Class Member Function
-
pointer ro member function
- 定义
需要指定其返回类型和参数列表,还需要指定它所指的究竟是哪个class。
将pm声明为一个指针,指向num_sequence的member function,后者的返回类型是void,并且只接受一个int参数。pm初始值为0代表不指向任何member function。
void (num_sequence::*pm)(int) = 0;
用typedef简化
typedef void (num_sequence::*PtrType)(int);
PtrType pm = 0;
- 初始化
在函数名称先先以class scope运算符加以限定,再应用取址&运算符。
pm = &num_sequence::fibonacci;
- 调用
通过同一类的对象调用,这个对象就是此member function内的this指针指向的对象。
- pointer ro member selection(.*)
针对class object,使用时要加外围小括号。
-
pointer ro class object(->*)
针对pointer to calss object,使用时也要加外围小括号。