C++学习9-运算符重载

运算符重载的意义

运算符重载,就是对已有的运算符赋予多重含义,使同一运算符作用于不同类型的数据时产生不同的行为。运算符重载的目的是使得 C++ 中的运算符也能够用来操作对象。
优点:
如果不做特殊处理,C++的 +、-、*、/ 等运算符只能用于对基本类型的常量或变量进行运算,不能用于对象之间的运算。
有时希望对象之间也能用这些运算符进行运算,以达到使程序更简洁、易懂的目的。例如,复数是可以进行四则运算的,两个复数对象相加如果能直接用+运算符完成,更加直观和简洁.

运算符重载的实质是编写以运算符作为名称的函数。不妨把这样的函数称为运算符函数。
运算符函数的格式如下:

返回值类型  operator  运算符(形参表)
{
    ....
}
包含被

重载的运算符的表达式会被编译成对运算符函数的调用,运算符的操作数成为函数调用时的实参,运算的结果就是函数的返回值。运算符可以被多次重载。

运算符可以被重载为全局函数,也可以被重载为成员函数。

运算符重载为成员函数

下面是运算符重载为成员函数,这样能够较好地体现运算符和类的关系:

#include <iostream>
using namespace std;
class Complex
{
public:
    double real, imag;
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { }
    Complex operator - (const Complex & c);
};
Complex operator + (const Complex & a, const Complex & b)
{
    return Complex(a.real + b.real, a.imag + b.imag); //返回一个临时对象
}
Complex Complex::operator - (const Complex & c)
{
    return Complex(real - c.real, imag - c.imag);  //返回一个临时对象
}
int main()
{
    Complex a(4, 4), b(1, 1), c;
    c = a + b;  //等价于 c = operator + (a,b);
    cout << c.real << "," << c.imag << endl;
    cout << (a - b).real << "," << (a - b).imag << endl;  //a-b等价于a.operator - (b)
    return 0;
}

程序的输出结果是:

5,5
3,3

解析:
有了对+的重载,编译器就将a+b理解为对运算符函数的调用,即operator+(a,b),因此第 21 行就等价于:
c = operator+(a, b);
即以两个操作数 a、b 作为参数调用名为operator+的函数,并将返回值赋值给 c。

运算符被重载为全局函数

class CComplex
{
public:
    CComplex(int r = 0, int i = 0)
        :mreal(r), mimage(i) {}
    ~CComplex() {}
    // 复数对象相加
    // CComplex comp3 = comp1 + comp2;
//定义加号运算符重载的成员函数
    CComplex operator+(/*this*/const CComplex &src)
    {
        return CComplex(mreal + src.mreal, mimage + src.mimage);
    }
frendly void operator+(int a, const CComplex &src);
//友元是声明,形参变量可以不用写 a和&src其实可以不用写 定义了友元才能访问私有成员变量
    void show()
    {
        cout << "real:" << mreal << " image:" << mimage << endl;
    }
private:
    int mreal;//实数
    int mimage;//虚数
};
//双目运算符的函数参数只能有两个,一个this 一个是传进来的.(成员方法中)
//所以这个加号重载只能写在全局 不然写成成员方法的话会默认传一个this指针,会变成三个参数
CComplex operator+(const CComplex &a, const CComplex &b)
{
        cout << "CComplex operator+(const CComplex &a, const CComplex &b)" << endl;
        return CComplex(a.mreal + b.mreal, a.mimage + b.mimage); //返回一个临时对象
}

int main()
{
    CComplex comp1(10, 10);
    CComplex comp2(20, 20);

    CComplex comp3 = comp1 + comp2;
    comp3.show();

    comp3 = comp1 + 20; // int => CComplex(int)
    //因为形参赋值从右向左,所以20会构造出对象给src,comp1传给this指针 所以这个可以用已经写好的成员函数进行运算
    comp3.show();

    comp3 = 20 + comp1;//一个内置类型的数加上复数
    //comp1会构造出对象给src,20不能转为临时变量给this 所以要定义全局函数,如果成员方法没有则调用全局函数
//编译器在做对象运算时,优先从成员方法中找合适的运算符重载函数,如果没有,会去全局再找合适的运算符重载函数
    comp3.show();

    return 0;
}

完整程序为:

#include<iostream>
using namespace std;
// 复数类
class CComplex
{
public:
        CComplex(int r = 0, int i = 0)
               :mreal(r), mimage(i)
        {
               cout << "CComplex(int r = 0, int i = 0)" << endl;
        }
        ~CComplex() //没访问外部资源,析构这就啥也不干(有指针就有可能会访问外部资源就要析构掉)所以也不用自己写拷贝构造和赋值重载
        {
               cout << "~CComplex" << endl;
        }
        
        CComplex& operator++()//前置加加
        {//自己加一遍 再把自己赋给别人 这个不产生临时对象 可以返回引用因为一直都用的是本身
               //返回的并不是临时量 所以子函数结束后return后面的值还在
               ++mreal;
               ++mimage;
               return *this;
        }
//为了区分前值和后置++ 所以规定后置的加一个(int)参数
        CComplex operator++(int)//后置加加
        {
               return CComplex(mreal++, mimage++);
//先构造临时对象=对象本身.然后再给对象本身++
               //所以一般我们会优先选择前置++来写
        }
        void operator=(const CComplex &src)//赋值
        {
               cout << "void operator=(const CComplex &src)" << endl;
               mreal = src.mreal;
               mimage = src.mimage;
        }//comp3 = 对象  opertor=(this(comp3),对象) 把等号后面的赋给前面的 所以不用返回值
        void operator+=(const CComplex &src)//a=a+b
        {
               mreal += src.mreal;
               mimage += src.mimage;
        }
        bool operator>(const CComplex &src)
        {
               return ((mreal>src.mreal)||((mreal == src.mreal)&&(mimage>src.mimage)));
        }
        bool operator<(const CComplex &src)
        {
               return ((mreal < src.mreal) || ((mreal == src.mreal) && (mimage <  src.mimage)));
        }
        bool operator==(const CComplex &src)
        {
               return ((mreal == src.mreal) && (mimage == src.mimage));
        }
        void show()
        {
               cout << "real:" << mreal << " image:" << mimage << endl;
        }
        friend CComplex operator + (const CComplex & a, const CComplex & b);
        friend ostream& operator<<(ostream &out, const CComplex &src);
        friend istream& operator>>(istream &cin, const CComplex &src);
private:
        int mreal;//实数
        int mimage;//虚数
};
//双目运算符的函数参数只能有两个,一个this 一个是传进来的.(成员方法中)
//所以这个加号重载只能写在全局 不然写成成员方法的话会默认传一个this指针,会变成三个参数
CComplex operator+(const CComplex &a, const CComplex &b)
{
        cout << "CComplex operator+(const CComplex &a, const CComplex &b)" << endl;
        return CComplex(a.mreal + b.mreal, a.mimage + b.mimage); //返回一个临时对象
}
ostream& operator<<(ostream &out, const CComplex &src)//输出 
{//这里的out就相当于cout对象了 所以可以这样写
        out << "real:" << src.mreal << " image:" << src.mimage << endl;
        return out;
}
//cout << comp1 << endl;双目运算符有两个参数,一个是输出流 一个是对象
//流不能用const修饰,因为流一直在变化
//istream& operator>>(istream &in, const CComplex &src)
//{
//      in >> src.mreal >> src.mimage;
//      return in;
//}
int main()
{
        CComplex comp1(10, 10);
        CComplex comp2(20, 20);
        
        cout << "=================" << endl;
        CComplex comp3 = comp1 + comp2;
        //临时对象构造对象直接变成对象的构造 临时对象的构造将不会产生
        comp3.show();
        cout << "============" << endl;
        
        // comp1.operator+(const CComplex &src)
        //comp3 = 对象  opertor=(this(comp3),对象)
        comp3 = comp1 + 20; // int => CComplex(int)
        comp3.show();
        comp3 = 20 + comp1;//一个内置类型的数加上复数
        //1.20 构造类对象
        //2.构造临时对象
        //3.赋值重载
        comp3.show();
        cout << "============" << endl;
        comp2 = comp1++;//
        comp1.show();
        comp2.show();
        cout << "============" << endl;
        comp2 = ++comp1;
        comp1.show();
        comp2.show();
        comp2 += comp1;
        comp1.show();
        comp2.show();
        if (comp1 > comp2)
        {
               cout<<"cmp1大"<<endl;
        }
        cout << "============" << endl;
        //  ostream& out, const CComplex &src
        cout << comp1 << endl;
//直接调用运算符重载函数 输出函数内的输出 对象不在左边所以不能写成成员函数
        cout << "============" << endl;
        //cin >> comp1;
        //comp1.show();
        return 0;
}

先找成员函数看是否有符合的,若没有则找全局函数.

构造和析构:

int main()
{
        CComplex comp1(10, 10);
        CComplex comp2(20, 20);
//CComplex(int r = 0, int i = 0)
//CComplex(int r = 0, int i = 0)  构造comp1,2
        cout << "=================" << endl;

        CComplex comp3 = comp1 + comp2;
//CComplex operator+(const CComplex &a, const CComplex &b)
//CComplex(int r = 0, int i = 0)  加号运算符重载 临时量直接构造对象
        //临时对象构造对象直接变成对象的构造 临时对象的构造将不会产
        cout << "============" << endl;

        comp3 = comp1 + 20; // int => CComplex(int)
//CComplex(int r = 0, int i = 0)     20构造对象
//CComplex operator+(const CComplex &a, const CComplex &b)  加号运算符重载
//CComplex(int r = 0, int i = 0)  comp1 + 20 构造临时对象
//void operator=(const CComplex &src)  等号运算符重载
//~CComplex  
//~CComplex

        comp3 = 20 + comp1;//一个内置类型的数加上复数
//CComplex(int r = 0, int i = 0)  20构造对象
//CComplex operator+(const CComplex &a, const CComplex &b)  加号运算符重载
//CComplex(int r = 0, int i = 0)      20 + comp1 构造临时对象
//void operator=(const CComplex &src)   等号运算符重载
//~CComplex
//~CComplex
        comp3.show();
        cout << "============" << endl;
        comp2 = comp1++;//
//CComplex(int r = 0, int i = 0)  构造临时对象=本身
//void operator=(const CComplex &src)   赋值重载
//~CComplex  析构临时对象
        cout << "============" << endl;
        comp2 = ++comp1;
//void operator=(const CComplex &src)  直接进行自身 加一遍 再把自己赋给别人
}

报错原因

如果程序报了大量的错:
1.头文件没包含string
2.对象没有运算符重载函数,直接做了运算

容易忘记做的有: 学生对象sort排序,比较大小就相当于在做运算,所以要提供大于/小于的运算符重载

发布了82 篇原创文章 · 获赞 7 · 访问量 4205

猜你喜欢

转载自blog.csdn.net/sunshine612/article/details/104671692