第11章 使用类
<c++ primer plus>第六版
目录
11 使用类
11.1 运算符重载
函数重载/函数多态: 定义多个名称相同但特征标不同的函数.
运算符重载是一种形式的c++多态, 将重载的概念扩展到运算符上.
运算符函数, 是一种特殊函数形式, 格式如下:
operatorop(argument-list);
其中op必须是有效的c++运算符, 不能虚构新运算符.
例如
operator+() //重载+运算符
operator*() //重载*运算符
operator[]() //重载[]运算符(数组索引运算符)
如下语句:
district2 = sid + sara; //编译器将使用运算符函数替换上述运算符:
district2 = sid.operator+(sara); //该函数隐式地使用sid, 显式地使用sara.
11.3 友元
通常, 访问类的途径只能通过公有类方法. 但这种限制太严, 所以提供了另外形式的访问权限: 友元.
友元有3种: 友元函数, 友元类, 友元成员函数.
为何需要友元函数:
对于 A = B * 2.75; 转换为 A = B.operator*(2.75);
但 A = 2.75 * B, 由于2.75不是自定义的类对象, 编译器没办法使用成员函数调用来替换该表达式.
解决方法:
- 限制只能按 B*2.75方式写, 这样对客户不友好.
- 使用非成员函数:
函数原型: Time operator(double m, const Time & t);
则 A = 2.75 * B; 替换为 A = operator(2.75, B);
但使用非成员函数引发了一个新问题: 常规非成员函数不能直接访问类的私有数据,
于是提出特殊的非成员函数, 它可以访问类的私有成员, 被称为友元函数.
11.3.1 创建友元
//第一步, 将原型放在类声明中, 并加friend关键字.
friend Time operator*(double m, const Time & t);
//第二步, 编写函数定义, 由于不是成员函数, 所以不需要Time::限定符. 且不需要在定义中使用friend关键字.
Time operator*(double m, const Time & t)
{
Time result;
... //访问t的私有数据
return result;
}
类的友元函数是非成员函数, 但访问权限与成员函数相同.
注意, 只有类声明可以决定哪些函数是友元, 因此类声明仍然控制了哪些函数可以访问私有数据.
11.3.2 常用的友元: 重载 << 运算符
cout是一个ostream对象, 它能够识别所有c++基本类型(因为对每个基本类型, ostream类声明中都包含了相应的重载的operator<<()定义).
要使cout能识别Time对象, 对<<进行重载, 可以这样显示对象:
cout << trip ;
一般来说, 要重载<<运算符来显示C_NAME的对象, 可以使用一个友元函数, 定义如下:
ostream & operator<<(ostream & os, const C_NAME & obj)
{
os << ...; //显示对象内容
return os;
}
11.4 重载运算符: 作为成员函数还是非成员函数.
加法运算重载
成员函数版本 :
Time operator+(const Time & t) const;
T1 = T2+T3 //转换为 T1 = T2.operator+(T3);
非成员函数版本:
friend Time operator+(const Time & t1, const Time & t2);
T1 = T2+T3 转换为 T1 = operator+(T2, T3);
成员函数版本少一个参数, 这个参数通过this指针隐式地传递.
11.5 再谈重载: 一个矢量类
11.6 类的自动转换和强制类型转换
兼容的内置类型的转换
long count = 8; //将整型值8转换为long类型
double time = 11; //将整型值11转换为double类型
int side = 3.33; //将双精度值3.33转为整型值3
不兼容类型不能自动转换
int * p = 10; //错误, 不能把整数赋值给指针
int * p = (int *) 10; //正确, 将10强制转为int指针类型(int *), 再将指针赋值给p.
11.6.1 转换函数
Stonewt wolfe(285.7); //double类型转换为Stonewt类型
double host = double(wolfe); //将Stonewt类型转换为double类型, 语法1.
double thinker = (double) wolfe; //将Stonewt类型转换为double类型, 语法2.
Stonewt wells(20, 3);
double star = wells; //左侧double, 右侧Stonewt, 编译器将寻找转换函数(如果找不到, 将报错)
转换函数的定义方法:
operator typeName();
如:
operator double(); //转换为double类型的函数
注意:
- 转换函数必须是类方法;
- 转换函数不能指定返回类型;
- 转换函数不能有参数;
#ifndef STONEWT1_H_
#define STONEWT1_H_
class Stonewt
{
...
public:
operator int() const;
operator double() const;
}
#endif
Stonewt::operator int() const //最后一个const表示是const函数, 不修改类成员
{
return int(pounds + 0.5);
}