C++ Primer Plus 11章 使用类

本文详细探讨了C++中类的使用,包括运算符重载、友元和类型转换。重点讲解了如何重载加法运算符、在运算符重载中使用构造函数、友元函数的作用及其在输入输出运算符中的应用。此外,还介绍了C++的自动类型转换和强制类型转换,以及转换函数的使用。文章通过实例解析了友元函数与成员函数的区别,并讨论了重载特殊运算符如=、()、[]和->的注意事项。
摘要由CSDN通过智能技术生成
第11章 使用类
思维导图

在这里插入图片描述

1.运算符重载

如下是一种实现加法运算的方式:

1.1 不应该返回对临时对象的引用
Time Time::Sum(const Time &t) const
{
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes/60;
    sum.minutes %= 60;
    return sum;
}

如果返回类型为Time类型的对象,在调用结束后,返回对象是sum副本,使得调用函数可以使用它。

然而如果返回类型是引用,也就是对局部变量sum引用,由于函数调用结束后局部变量将会被删除,因此引用将会指向一个不存在的对象。

1.2 加法运算符的重载
//方法声明
Time operator+(const Time & t) const;
//方法定义
Time Time::operator+(const Time & t) const
{
    ...
}
//方法调用
total = coding.operator+(fixing);
total = coding + fixing;

方法调用时,运算符左侧的对象是调用对象(被隐式使用),运算符右侧的对象是作为参数被传递的对象(被显式使用)。

注意重载后的运算符至少有一个操作数是用户定义的数据类型。

重载后缀++运算符:

CTimer operator++(int);	//后缀++
1.3 在运算符重载方法定义中使用构造函数

如果方法通过计算要得到一个新对象,可以考虑使用构造函数来完成工作。使用构造函数可以避免麻烦,并确保新的对象是按照正确的方式创建的。

Vector Vector::operator+(const Vector &b) const
{
    return Vector(x + b.x, y + b.y);
}
2. 友元

友元函数是非成员函数,但有访问类成员数据的权限,一般处理对象不是第一个操作数运算符重载问题。

友元函数可以视作一部分类的扩展接口

2.1 友元的必要性

假设A和B是某个用户定义类型的对象,实现了加法运算符的重载,那么:

A = B + 2.75,相当于A = B.operator+(B)

但是例如A = 2.75 + B 却无法通过类成员函数实现,所以需要一种非成员函数,它使用的所有值都是显式参数。

2.2 友元的简单创建与使用

1.声明

友元函数在类声明中声明,但它不是成员函数,不能使用成员运算符调用。

//将原型放在类声明中
friend Time operator*(double m, const Time & t);

2.定义

友元函数的定义中不要出现限定符Time::和关键字friend

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

友元函数和成员函数有着相同的访问权限,都可以访问类的私有成员。

但是友元函数在访问时需要加上成员运算符或作用域解析运算符,如果Vector类中存在枚举enum Mode {RECT, POL}; 由于友元函数不在类作用域内,因此必须使用Vector::RECT,而不能使用RECT

3.友元函数的替换

不使用友元函数,可以实现同样的功能。但是也可以将其设置为友元函数。

Time operator*(double m, const Time & t) 
{
	return t*m;	//调用类方法
}
2.3 重载输入输出运算符
#include <iostream>
...
friend std::ostream & operator<<(std::ostream & os, const Time & t);

该函数需要访问Time对象的数据成员,是Time的友元函数;将ostream对象作为一个整体来使用,不访问它的数据成员,因此不是ostream的友元函数。

由于需要考虑cout << "Trip time:" << trip;的情况,因此operator<<函数的返回值应该为指向ostream对象的引用。

std::ostream & operator<<(std::ostream & os, const Time & t)
{
    os << t.hours << t.minutes;
    return os;
}

重载输入运算符:

friend std::istream& operator>>(std::istream& is, CTimer &t);
3.类的自动转换和强制类型转换

在这里插入图片描述

3.1 C++对内置类型的转换方式

1.自动转换

如果类型兼容,C++自动将这个值转换为接收变量的类型;

比如double time = 11;,自动将int类型转换为double

2.强制类型转换

如果类型不兼容,可以使用强制类型转换

比如int *p = (int *) 10;,这里必须使用强制类型转换。

3.2 构造函数用作自动类型转换函数

1.构造函数的条件

在C++中,接受一个参数构造函数可以作为自动类型转换函数。从而实现从参数类型类类型的转换。

//构造函数声明
Stonewt(double lbs);
//自动类型转换
Stonewt myCat;
myCat = 19.6;

2.自动类型转换的过程

程序将先使用该构造函数创建一个临时对象,用19.6对临时对象进行初始化,然后将临时对象逐成员复制到myCat中,最后临时对象被删除。

3.可自动转换的类型

当转换不存在二义性时,Stonewt(double lbs)也可以用于转换其它数值类型,例如Stonewt Jumbo(700);Jumbo = 700;都会先将int转换为double,然后在调用Stonewt(double lbs)构造函数。

4.关闭自动类型转换

使用explicit关键字用于关闭这种自动特性

//构造函数声明
explicit Stonewt(double lbs);
//强制类型转换
Stonewt myCat;
myCat = Stonewt(19.6);

5.自动类型转换的发生时机

Stonewt对象初始化double值时;

double赋值Stonewt对象时;

double值传递给接收Stonewt参数的函数时;

返回值被声明为Stonewt类型的函数试图返回double值时。

3.3 转换函数

构造函数用于从某种类型到类类型的转换。如果要做类类型到其它类型的转换,需要用到转换函数

转换函数的形式:

operator typeName();

转换函数的特点:

1.必须是类方法

2.不能指定返回类型

3.不能有参数

转换函数的声明和定义:

operator int() const;
Stonewt::operator int() const
{
    return int(pounds + 0.5);	//基本类型间的显式类型转换
}

转换函数的使用方法:

Stonewt wolfe(285.7);
int host = int(wolfe);

可以使用explicit避免自动的隐式类型转换:

explicit operator int() const;

3.4 友元函数、运算符重载、转换函数

使double类型的值与Stonewt类型的值相加的方法:

1.使用友元函数

friend Stonewt operator+(const Stonewt &, const Stonewt &);

优点是程序简短,缺点是每次都需要调用转换函数,增加了时间和内存开销。

2.重载加法运算符,显式使用double类型的参数

Stonewt operator+(double x);
friend Stonewt operator+(double x, Stonewt & s);

优点是不需要调用转换函数,运行速度较快;缺点是程序较长。

4.课后题
1.友元函数和成员函数之间的区别是什么?

函数调用方式访问对象成员的方法两个角度:

成员函数是类定义的一部分,通过特定的对象来调用;

成员函数可以隐式访问对象的成员,而无需使用成员运算符。

友元函数不是类的组成部分,被称为直接函数调用

友元函数不能隐式访问对象的成员,必须对作为参数传递的对象使用成员运算符

2.非成员函数必须是友元才能访问类成员吗?

如果访问类的私有成员,必须是友元;

如果访问类的公有成员,可以不是友元。

3.哪些运算符不能重载?

sizeof..*::?:

4.在重载运算符=、()、[]和->时,有什么限制?

只能使用类成员函数进行重载,不能使用友元函数进行重载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值