【第八章】操作符重载的概念

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/78176303

作为成员函数的操作符


operator+= 需要一个左值。 需要通过现有对象(左值)来调用类似+=这样的操作符,这些对象将修改左值。

●如果操作符 “+=” 必须通过现有对象来调用,那么便可将该操作符实现为成员函数。 通过非对象不能调用操作符“+=”,因为它需要修改调用它的对象。

● 注意: 一般而言,如果重载操作符需要一个左值(它将修改第1个操作数),那么, 可将其作为成员函数来实现。

这表明,只能通过现有对象调用这样的操作符(作为成员函数实现的操作符)。 所有具有赋值操作符特色的其他操作符(+= -= *= /=)都可以作为成员函数来实现。

● 实现重载操作符有两个十分重要的规则:

(1) 任何不需要左值和互换的操作符,最好作为非成员函数(+ - 等)实现。 这允许编译器在参数不匹配的情况下转换第1个参数

(2) 任何需要左值的操作符最好作为成员函数实现。 这清楚地表明只能通过现有的、可修改的对象调用它。


作为非成员函数实现的操作符


能以单个参数调用的构造函数称为转换构造函数。 它规定了从它的(第一个)参数类型转换为它的类(构造函数所属于的类)类型。 如果转换构造函数没有用explicit 限定符声明, 那么,在需要时将进行隐式转换(使用转换构造函数)


 class X
 {
 public:
     explicit X(int i); //只在显式要求时才进行转换
 };

 void f(X a){}

 int main()
 {
     int i = 0;
     f(i); //不会运行,因为X(int) 不是一个转换构造函数
     f(X(i));// 运行,要求显式转换
 }

只有在被调用的函数是非成员函数时,才会转换(由用户单独明确地定义)表达式的第一个参数。被调用的函数是成员函数时,不转换它的第一个参数。

● 注意: 对每个值只能进行一次转换。 只有不存在二义性才能进行转换。如果应用转换引起了多个重载函数匹配,则不进行转换,因为调用不够明确。

如果未找到直接匹配的函数,无论是成员函数还是非成员函数,都将转换(由用户单独明确地定义)它们的第二个参数和后续的参数。

任何不需要左值和互换的操作符,最好作为非成员函数(+ - 等)实现。 这允许编译器在参数不匹配的情况下转换第1个参数

● 需要左值却不需要互换的操作(如+=、-= 等), 不用转换第一个参数。对于这样的操作符,应该作为成员函数实现。

这里写图片描述


转换构造函数


转换构造函数的作用是将一个其他类型的数据转换成一个类的对象。注意:转换构造函数只能有一个参数。如果有多个参数,就不是转换构造函数。(当一个构造函数只有一个参数,而且该参数又不是本类的const引用时,这种构造函数称为转换构造函数。)

转换构造函数的作用是将某种类型的数据转换为类的对象。


● 下面的转换构造函数,将int类型的r转换为Student类型的对象,对象的age为r,num为1004.

 Student(int r)
 {
     int num=1004int age= r;
 }

注意 :转换构造函数也是构造函数重载的一种,但是转换构造函数只能有一个参数,如果有多个参数就不是转换构造函数。原因:如果有多个参数,无法确认把哪一个参数

注意: 如果不想让转换构造函数生效,也就是拒绝其它类型通过转换构造函数转换为本类型,可以在转换构造函数前面加上explicit,用来抑制隐式转换


#include <iostream>  
using namespace std;  

class Complex  
{  
public:  
    Complex()       //默认构造函数  
    {  
        real = 0;  
        imag = 0;  
        cout << "调用默认构造函数" << endl;  
    }  
    Complex(double r,double i):real(r),imag(i)        //有参数的初始化构造函数,并用初始化表进行初始化  
    {  
        cout << "调用有参数的初始化构造函数" << endl;  
    }  
    Complex(double i)                                 //转换构造函数,对传入的参数进行转换成对象  
    {  
        real = i;  
        imag = 0;  
        cout << "调用转换构造函数" << endl;  
    }  
    void Display()  
    {  
        cout << real << "+" << imag << "i" << endl;  
    }  
private:  
    double real;  
    double imag;  
};  
int main()  
{  
    Complex C1;  
    C1.Display();  
    Complex C2(2,2);  
    C2.Display();  
    Complex C3(1.2);  
    C3.Display();  
    return 0;  
}  

那么 s1+19 呢(类对象与int直接相加)?

因为我们定义了 转换构造函数,那么 s1+19,执行如果过程:

(1)首选调用+号运算符,发现19不是Student类的对象,而是int类型

(2)然后调用转换构造函数,将19变为Student(19)

(3)现在便可以进行加法运算。


转换函数


● 用转换构造函数可以将一个指定类型的数据转换为类的对象,但是不能反过来将一个类的对象转换为一个其他类型的数据。 类型转换函数的作用是将一个类的对象转换成另一个类型的数据。

类型转换函数的语法格式为:

operator 类型名()
{
   return object;
}

注意 : 类型转换函数在函数名前不能指定函数类型,也没有参数返回类型是类型名决定的,只能作为成员函数,因为转换的类型是本类的对象不能作为友元函数或者普通函数。 它还可以是虚函数,还可以被继承。对一个值最多只能进行一次用户定义的转换(转换构造函数或转换函数)。


#include<iostream>
using namespace std;
class Student
{
private:
    float score;
    int age;
public:
    Student(void)
    {
        cout << "默认构造函数被调用!" << endl;
        age = 18;
        score = 0;
    }
    Student(int a, float s)
    {
        cout << "带参数的构造函数被调用!" << endl;
        age = a;
        score = s;
    }
    operator float()
    {
        cout << "转换函数被调用!" << endl;
        return score;
    }
};

int main()
{
    Student stu1(18, 86), stu2(18, 97.5);
    float f = 6.75 + stu2;   //调用转换函数,加法的时候不需要重载“+”,但是如果把6.75 转换为“Student”对象,然后执行加法,需要重载“+”;

    cout << "输出f的值:" << f << endl;
    system("pause");
    return 0;
}

这里写图片描述


● 转换函数不仅限于内置类型,它还可以从一个类转换为另一个类

● 在类中随意添加转换构造函数和转换函数不是个好习惯,因为它们同时存在可能导致二义性。


消除对临时对象的需求


● 还有一个需要说明的问题。通过构造函数转换函数进行的转换,都创建了临时对象。 在使用转换构造函数时,创建了临时对象

对于每个创建的对象, 都需要调用构造函数和析构函数(在删除临时对象时)。 这极大地增加了程序的执行时间。

对于大多数从类转换为内置类型的转换函数,会创建一个临时变量(不是对象)。 创建一个内置类型变量(如 int) 比创建一个对象的开销要小的多。

应该考虑尽量避免创建临时对象的方案。 注意: 在许多情况下, 避免临时对象都是一个好的编程习惯, 而不仅限于重载操作符。


从操作符函数返回结果


●左值操作符(通过现有对象调用的操作符) 可以返回对操作符左边对象(操作符调用的目标)的引用。 这是实现左值操作符安全、高效、正确的方式

● 根据操作数计算出结果的可互换操作符(+、 - 等 ),不能返回引用或指针。 这样的操作符要按值返回。

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/78176303
今日推荐