Primer Plus 使用类

运算符重载

运算符左侧的对象是调用对象,右侧的对象是作为参数被传递的对象

友元函数

通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限

一个使用场景:要为类重载运算符,第一个操作数是非类项(普通的运算符重载左侧得是调用对象),就可以用友元反转操作数顺序

常用的友元:重载<<运算符

ostream类对基本类型都重载了<<运算符,因此cout作为ostream对象有输出能力

要让cout能识别自己的类,一种方法是改iostream文件,一种是通过友元函数让自己的类知道怎么使用ostream对象

1
2
3
4
5
// 返回ostream的引用,以实现cout << x << y,其等价于(cout << x) << y
ostream & operator <<(ostream & os, const class_name & obj) {
os << ...; // 具体要打印的东西
return os;
}

重载运算符:作为成员函数还是非成员函数

对于=,(),[],->这四个运算符,只能通过成员函数重载

类的自动转换和强制类型转换

只有一个参数的构造函数可用于提供类的隐式转换

1
2
3
4
5
6
7
8
9
10
// 类Stonewt有这样一个构造函数
Stonewt(double lbs);

// 那么下面的语句相当于调用了构造函数
Stonewt myCat;
myCat = 19.6;

// 这样也可以,int先转换成double再转换成Stonewt
// 如果Stonewt还有一个参数类型为long的构造函数,就不能这样,int的转换不能有二义性
myCat = 7300;

多个参数的构造函数不能这样,除非后面几个参数有默认值

explicit关键字可以关闭这种特性

1
2
3
4
5
6
7
// 类Stonewt有这样一个构造函数
explicit Stonewt(double lbs);

Stonewt myCat;
myCat = 19.6; // 非法
myCat = Stonewt(19.6); // 合法,显式的转换仍然允许
myCat = (Stonewt)19.6; // 合法

类还可以声明转换函数

1
2
3
4
5
6
7
8
9
10
11
12
13
class Stonewt {
private:
double pounds;
public:
operator double() const;
};

Stonewt::operator double() const {
return pounds;
}

Stonewt haha(666.6);
double x = haha; // 如果有转换函数就合法

C++11以后,转换函数也能加explicit修饰,这样防止不想要的隐式转换,只有强制转换时才会调用转换函数

重载运算符时,用友元和用成员函数的一个区别

1
2
3
4
5
6
7
8
// 假设Stonewt有Stonewt(double)构造函数
// 那么不论用成员函数还是用友元函数重载加法,下面语句都合法
Stonewt a(100, 666);
double b = 666.666;
Stonewt c = a + b;

// 但是下面的语句只有友元函数合法
stonewt c = b + a;