《C++ Primer Plus》(第6版)中文版—学习笔记—使用类

第11章 使用类

书中课后练习将在https://github.com/linlll/CppPrimePlus发布

运算符重载

运算符重载是一种形式的C++多态。这符合C++语言的特性——面对对象,C++语言有很多我们自己定义的数据类型,那当我们想要进行基本运算的时候,会发现有一定的局限性,就比如说,在C语言中,想要实现两个等长数组的各个元素相加,我们只能使用for或者while循环进行相加并赋值,但是在C++中,我们可以定义一个表示数组的类,在类中可以重载运算符,对其进行你想要的操作,在使用的时候,表示法和基本的运算符是一样的操作,例如arr1 = arr2 + arr3,要重载运算符,需使用被称为运算符函数的特殊函数形式,格式如下:

operatorop(argument-list)
// eg
operator+();
operator*();

具体做法看下一节

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

让我们看看不使用运算符重载的一个示例,这是一个表示时间的类。

class Time
{
    
    
private:
    int hours;
    int minutes;
public:
    Time();
    Time(int h, int m = 0);
    void AddMin(int m);
    void AddHr(int h);
    void Reset(int h = 0, int m = 0);
    const Time Sum(const Time & t) const;
    void Show() const;
};

上面是一个表示时间的类的声明,有相加,重置等运算,再看重载运算符后的类的声明。

class Time
{
    
    
private:
    int hours;
    int minutes;
public:
    Time();
    Time(int h, int m = 0);
    void AddMin(int m);
    void AddHr(int h);
    void Reset(int h = 0, int m = 0);
    Time operator+(const Time & t) const;
    void Show() const;
};

可以看出对之前的Sum函数进行修改,利用运算符重载进行重新定义函数,使用这种函数的时候,我们可以使用函数表示法和运算符表示法,例如

Time a(1, 30);
Time b(2, 20);
Time c = a.operator+(b);
Time d = a + b;

其中,最后两句的效果是一样的。


但是对运算符重载是有限制的

请看原文。

友元

类介绍到这里,我们都知道类中的私有成员是不可以外界访问的,只能通过类中的共有成员对其进行访问,也就是说只有作用域在类中的成员才能访问,作用域不同是不能访问其私有成员的,但是这种限制太过严格,将会不适合特定的编程问题。C++提供了友元访问权限,这将使得我们可以访问类中的私有成分。

友元分为三种:

  1. 友元函数
  2. 友元类
  3. 友元成员函数

本章先讲友元函数。

重载*运算符

为什么需要友元呢?我们在重载二元运算符的时候就常常需要友元。例如之前提到的Time类,重载了一个乘法运算符,运算写法为A = B * 2.75,可以看到A和B都是类,但是2.75为一个基本数据类型double,这样的写法是合理的,因为编译器会将其认为A = B.operator*(2.75),也就是说,这个乘法运算是调用类B中所重载的那个乘法。但是可否写成A = 2.75 * B呢,答案是不行,因为,2.75是一个基本类型,并没有任何的函数,所以我们必须重载一个以double为第一参数的乘法函数,满足客户需求。

那么函数原型就出来了:Time operator*(double m, const Time & t),其用法为:A = 2.75 * B; A = operator*(2.75, B),那么问题来了,这个函数原型是不能访问Time类中的私有成员的,从而导致这个函数根本不能使用,那么就有了友元函数了,友元函数可以大肆访问类的私有成员。


创建友元函数需要在函数原型面前加上关键字friend,例如

friend Time operator*(double m, const Time & t);

该原型意味着下面两点:

  • 虽然operator*()函数是在类声明中声明的,但是他不是成员函数,因此不能使用成员运算符来调用
  • 虽然operator*()函数不是成员函数,但他与成员函数的访问权限相同。

因为operator*()函数不能算是类中的成员函数,所以它的作用域不是这个类,也就是说在定义的时候不需要加上作用域限定符::,另外,在函数定义的时候不能够加上friend关键字。


实际上对于这个乘法重载,也可以写成一个非友元函数
例如

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

这实际上是利用了类中的成员函数。


重载<<运算符

class Time
{
    
    
	...
	friend std::ostream & operator<<(std::ostream & os, const Time & t);
}

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

看原文

再谈重载:一个矢量类

看原文

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

当构造函数接受一个参数的时候,我们可以使用构造函数进行显式或隐式的类型转换。也可以通过在类中定义一个转换函数进行类型转换,但是在转换类型的时候必须考虑二义性,编译器一旦发现二义性的问题,便会报错。

猜你喜欢

转载自blog.csdn.net/weixin_49643423/article/details/108099508
今日推荐