C++ Primer Plus第六版-第十一章-学习笔记

第 11 章 使用类

不要觉得必须使用所有的特性,不要在第一次学习时就试图使用所有的特性。 ——Bjarne Stroustrup

11.1 运算符重载

要重载运算符,需要使用被称为运算符函数的特殊函数形式。

operator p(argument-list)

如果distric2、sid和sara都是Salesperson类对象,可以编写这样的等式:

distric2 = sid + sara;
distric2 = sid.operator + (sara); //相应的运算符函数替换上述运算符,隐式使用sid,显示使用sara

11.2 计算时间:一个运算符重载示例

不要返回指向局部变量或临时变量的引用。函数执行完毕之后,局部变量和临时对象将消失,引用将指向不存在的数据。

重载限制

  1. 重载后的运算符必须至少有一个操作数是用户定义的类型
  2. 使用运算符时不能违反运算符原来的句法规则
  3. 不能创建新运算符
  4. 不能重载下面的运算符:P387
  5. 表11.1中的大多数运算符都可以通过成员或非成员函数进行重载,但下面的运算符只能通过成员函数进 行重载:
  • =:赋值运算符
  • ():函数调用运算符。
  • []:下标运算符
  • ->:通过指针访问类成员的运算符

11.3 友元

  • 友元函数
  • 友元类
  • 友元成员函数
    有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。

11.3.1 创建友元

创建友元函数的第一步是将其原型放在类声明中,并在原型声明前加上关键字friend:

friend Time operator*(double m, const Time& t); //goes in class declaration
  • 虽然operator*()函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
  • 虽然operator*()函数不是成员函数,但它与成员函数的访问权限相同。

第二步是编写函数定义。因为它不是成员函数,所以不要使用Time::限定符。另外,不要在定义中使用关键字friend,定义如下:

Time operator*(double m, const Time& t)
{
}

类的友元函数是非成员函数,其访问权限与成员函数相同。

Time operator*(double m, const Time& t)
{
	return t * m;
}  //这个版本将Time对象t作为一个整体使用,让成员函数来处理私有值,因此不必是友元。
//然而作为友元也是一个好主意!

如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以用友元函数来翻转操作数的顺序

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

  1. <<的第一种重载版本
    使用友元函数,可以像下面这样重载运算符:
void operator<<(ostream& os, const Time& t)
{
	os << t.hours << " hours, " << t.minutes << " minutes";
}   //这样可以使用下面的语句
cout << trip;
  1. <<的第二种重载版本
    前面介绍的实现存在一个问题。不允许像通常那样将重新定义的<<运算符与cout一起使用
    可以对友元函数采用相同的方法。只要修改operator<<()函数,让它返回ostream对象的引用即可:
ostream& operator<<(ostream& os, const Time& t)
{
	os << t.hours << " hours, " << t.minutes << " minutes";
	return os;
}

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

一般来说,非成员函数应该是友元函数,这样它才能直接访问类的私有数据。
加法运算符需要两个操作数。对于成员函数版本来说,一个操作数通过this指针隐式地传递,另一个操作数作为函数参数显示传递;对于友元版本来说,两个操作数都作为参数来传递。

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

只接受一个参数的构造函数才能作为转换函数。若有两个参数,则当为第二个参数提供默认值时,它便可用于转换。
将构造函数用作自动类型转换函数似乎是一项不错的特性。C++新增了关键字explicit,用于关闭这种自动特性
只接受一个参数的构造函数定义了从参数类型到类类型的转换。
如果在声明中使用了关键字explicit,则Stonewt(double)将只能用于显示强制类型转换,否则还可以用于下面的隐式转换。

  • 将Stonewt对象初始化为double值时。
  • 将double值赋给Stonewt对象时。
  • 将double值传递给接受Stonewt参数的函数时。
  • 返回值被声明为Stonewt的函数试图返回double值时。
  • 在上述任意一种情况下,使用可转换为double类型的内置类型时。

转换函数

构造函数只用于从某种类型到类类型的转换。
转换函数是用户定义的强制类型转换,可以像使用强制类型转换那样使用它们。用于将类对象转换为其他类型
如何创建转换函数呢:

operator typeName();
  1. 转换函数必须是类方法
  2. 转换函数不能指定返回类型;
  3. 转换函数不能有参数。

实现加法时的选择

要将double量和Stonewt量相加,有两种选择:

  1. 让Stonewt(double)构造函数将double类型的参数转换为Stonewt类型的参数,然后将下面的函数定义为友元函数:
operator+(const Stonewt&, const Stonewt& )
  1. 将加法运算符重载为一个显示使用double类型参数的函数:
Stonewt operator+(double x); //member function
friend Stonewt operator+(double x, Stonewt& s);

第一种方法程序简短,但时间和内存开销大
第二种方法运行速度快

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑着的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值