类和对象(17)—— 操作符重载

1、操作符重载的基本语法

  所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。

  运算符也可以重载。实际上,我们已经在不知不觉之中使用了运算符重载。例如,大家都已习惯于用加法运算符”+”对整数、单精度数和双精度数进行加法运算,如5+8,5.8+3.67等,其实计算机对整数、单精度数和双精度数的加法操作过程是很不相同的,但由于C++已经对运算符”+”进行了重载,所以就能适用于int,float,doUble类型的运算。

  又如”<<“是C++的位运算中的位移运算符(左移),但在输出操作中又是与流对象cout配合使用的流插入运算符,”>>“也是位移运算符(右移),但在输入操作中又是与流对象cin配合使用的流提取运算符。这就是运算符重载(operator overloading)。C++系统对”<<“和”>>“进行了重载,用户在不同的场合下使用它们时,作用是不同的。对”<<“和”>>“的重载处理是放在头文件stream中的。因此,如果要在程序中用”<<“和”>>”作流插入运算符和流提取运算符,必须在本文件模块中包含头文件stream(当然还应当包括”using namespace std“)。现在要讨论的问题是:用户能否根据自己的需要对C++已提供的运算符进行重载,赋予它们新的含义,使之一名多用。

   运算符重载的本质是函数重载。

   重载函数的一般格式如下:

函数类型 operator操作符名称 (形参列表)
{
    重载实体;
}

  operator 运算符名称 在一起构成了新的函数名。比如

const Complex operator+(const Complex &c1, const Complex &c2);

  我们会说,operator+ 重载了重载了运算符+。

2、操作符重载的规则

(1)C++不允许用户自己定义新的运算符,只能对已有的 C++运算符进行重载。

  例如,有人觉得 BASIC 中用“* *”作为幂运算符很方便,也想在 C++中将“**”定义为幂运算符,用“3* *5”表示 35,这是不行。

(2)C++允许重载的运算符

  C++中绝大部分运算符都是可以被重载的。

   不能重载的运算符只有 4 个:

  前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符合sizeof 运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。

(3)重载不能改变运算符运算对象(即操作数)的个数。

  如,关系运算符“>”和“<”等是双目运算符,重载后仍为双目运算符,需要两个参数。运算符”+“,”-“,”*“,”&“等既可以作为单目运算符,也可以作为双目运算符,可以分别将它们重载为单目运算符或双目运算符。
(4)重载不能改变运算符的优先级别。

  例如”*“和”/“优先级高于”+“和”-“,不论怎样进行重载,各运算符之间的优先级不会改变。有时在程序中希望改变某运算符的优先级,也只能使用加括号的方法 强制改变重载运算符的运算顺序。 

(5)重载不能改变运算符的结合性。

  如,复制运算符”=“是右结合性(自右至左),重载后仍为右结合性。

(6)重载运算符的函数不能有默认的参数

  否则就改变了运算符参数的个数,与前面第(3)点矛盾。

(7)重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一 个是类对象(或类对象的引用)。

  也就是说,参数不能全部是 C++的标准类型,以防止用户修改用于标准类型数据成 员的运算符的性质,如下面这样是不对的:

  复制代码 代码如下:

int operator + (int a,int b)

{
  return(a-b);

}

  原来运算符+的作用是对两个数相加,现在企图通过重载使它的作用改为两个数相 减。如果允许这样重载的话,如果有表达式 4+3,它的结果是 7 还是 1 呢?显然,这是 绝对要禁止的。

(8)用于类对象的运算符一般必须重载,但有两个例外,运算符”=“和运算符”&“不 必用户重载。

  复制运算符”=“可以用于每一个类对象,可以用它在同类对象之间相互赋值。因 为系统已为每一个新声明的类重载了一个赋值运算符,它的作用是逐个复制类中的数据 成员地址运算符&也不必重载,它能返回类对象在内存中的起始地址。
(9)应当使重载运算符的功能类似于该运算符作用于标准类型数据时候时所实现的功能。

  例如,我们会去重载”+“以实现对象的相加,而不会去重载”+“以实现对象相减的功能,因为这样不符合我们对”+“原来的认知。

(10)运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类 的成员函数也不是友元函数的普通函数。

 3、双目和单目操作符重载

 (1)双目

案例一:复数相加

普通方法实现复数相加

  利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << ")" << endl;
    }

    friend Complex complexAdd(Complex &c1, Complex&c2);
private:
    int a;//实部
    int b;//虚部
};

Complex complexAdd(Complex &c1, Complex&c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = complexAdd(c1, c2);
    c3.printComplex();

    return 0;
}

  利用成员函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << ")" << endl;
    }
    Complex complexAdd(Complex&another)
    {
        Complex temp(this->a + another.a, this->b + another.b);
        return temp;
    }

private:
    int a;//实部
    int b;//虚部
};

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3=c1.complexAdd(c2);
    c3.printComplex();

    return 0;
}

操作符重载方法实现复数相加:

   利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend Complex operator+(Complex &c1, Complex &c2);

private:
    int a;//实部
    int b;//虚部
};

Complex operator+(Complex &c1, Complex &c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}

int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = c1 + c2;//等同于Complex c3=operator+(c1, c2);
    c3.printComplex();

    return 0;
}

  利用成员函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a,int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    Complex operator+(Complex &another)
    {
        Complex temp(this->a + another.a, this->b + another.b);
        return temp;
    }

private:
    int a;//实部
    int b;//虚部
};


int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);

    c1.printComplex();
    c2.printComplex();

    Complex c3 = c1 + c2;//等同于Complex c3=c1.operator+(c2);
    c3.printComplex();

    return 0;
}

案例二:+=操作符

操作符重载方法实现+=

  利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend Complex & operator+=(Complex &c1,Complex &c2);

private:
    int a;//实部
    int b;//虚部
};

Complex & operator+=(Complex &c1,Complex &c2)
{
    c1.a += c2.a;
    c1.b += c2.b;

    return c1;
}

int main(void)
{
    Complex c1(1, 2);
    Complex c2(3, 4);

    c1.printComplex();//(1, 2i)    
    c2.printComplex();//(3, 4i)

    (c1 += c2) += c2;
    c1.printComplex();//(7, 10i)
    c2.printComplex();//(3, 4i)

    return 0;
}

   利用成员函数函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    Complex& operator+=(Complex &another)
    {
        this->a += another.a;
        this->b += another.b;

        return *this;
    }

private:
    int a;//实部
    int b;//虚部
};


int main(void)
{
    Complex c1(1, 2);
    Complex c2(3, 4);

    c1.printComplex();//(1, 2i)    
    c2.printComplex();//(3, 4i)

    (c1 += c2) += c2;
    c1.printComplex();//(7, 10i)
    c2.printComplex();//(3, 4i)

    return 0;
}

(2)单目

案例三:前++

操作符重载方法实现复数的前++操作

  利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend Complex & operator++(Complex &c);

private:
    int a;//实部
    int b;//虚部
};

Complex & operator++(Complex &c)
{
    c.a++;
    c.b++;
    return c;
}
int main(void) { Complex c1(1, 2); c1.printComplex();//(1, 2i) ++c1; c1.printComplex();//(2, 3i) return 0; }

  利用成员函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    Complex & operator++()
    {
        this->a++;
        this->b++;
        return *this;
    }

private:
    int a;//实部
    int b;//虚部
};


int main(void)
{
    Complex c1(1, 2);
    c1.printComplex();//(1, 2i)    

    ++c1;
    c1.printComplex();//(2, 3i)

    return 0;
}

案例四:后++

操作符重载方法实现复数的后++操作

  利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend const Complex operator++(Complex &c, int);

private:
    int a;//实部
    int b;//虚部
};

//重载的是后++操作符
const Complex operator++(Complex &c,int)
{
    Complex temp(c.a, c.b);
    c.a++;
    c.b++;

    return temp;
} 

int main(void)
{
    Complex c(1, 2);
    c.printComplex();//(1, 2i)    

    c++;
    c.printComplex();//(2, 3i)

    return 0;
}

  利用成员函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    const Complex operator++(int)//用const修饰函数返回值就不能实现连加c++++,只能后++一次
    {
        Complex temp(this->a, this->b);
        this->a++;
        this->b++;

        return temp;
    }

private:
    int a;//实部
    int b;//虚部
};

int main(void)
{
    Complex c(1, 2);
    c.printComplex();//(1, 2i)    

    c++;
    c.printComplex();//(2, 3i)

    return 0;
}

案例五:左移操作符<<

操作符重载方法实现复数的<<操作

  利用全局函数实现:

#include <iostream>
using namespace std;

class Complex
{
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printComplex()
    {
        cout << "(" << this->a << "," << this->b << "i)" << endl;
    }

    friend ostream& operator<<(ostream &os, Complex &c);

private:
    int a;//实部
    int b;//虚部
};

ostream& operator<<(ostream &os,Complex &c)
{
    os << "(" << c.a << "," << c.b << "i)";

    return os;
}

int main(void)
{
    Complex c(1, 2);
    cout<<c;    

    return 0;
}

案例六:右移操作符>>

#include <iostream>
using namespace std;
class Complex { public: Complex(int a, int b) { this->a = a; this->b = b; } void printComplex() { cout << "(" << this->a << "," << this->b << "i)" << endl; } friend ostream& operator<<(ostream &os, Complex &c);
friend istream& operator>>(istream &is, Complex &c);
private: int a;//实部 int b;//虚部 }; ostream& operator<<(ostream &os, Complex &c) { os << "(" << c.a << "," << c.b << "i)"; return os; } istream& operator>>(istream &is,Complex &c) { cout << "a:"; is>> c.a; cout << "b:"; is >> c.b; return is; } int main(void) { Complex c(1, 2); cin >> c; cout << c << endl; return 0; }

  注意:左移操作符<<只能写在全局,不能够写在成员方法中,否则调用的顺序会变反,c<<cout;

 案例七:等号=操作符重载

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Student
{
public:
    Student()
    {
        this->id = 0;
        this->name = NULL;
    }

    Student(int id, char *name)
    {
        this->id = id;

        int len = strlen(name);
        this->name = new char[len + 1];
        strcpy(this->name, name);
    }

    void printS()
    {
        cout << name << endl;
    }

    ~Student()
    {
        if (this->name != NULL)
        {
            delete[]this->name;
            this->name = NULL;
            this->id = 0;
        }
    }

    Student(const Student &another)
    {
        this->id = another.id;

        int len = strlen(another.name);
        this->name = new char[len + 1];
        strcpy(this->name, another.name);
    }

    Student & operator=(const Student &another)
    {
        //1、防止自身赋值
        if (this == &another)
        {
            return *this;
        }

        //2、先将自身的额外开辟的空间回收掉
        if (this->name != NULL)
        {
            delete[] this->name;
            this->name = NULL;
            this->id = 0;
        }

        //3、执行深拷贝
        this->id = another.id;
        
        int len = strlen(another.name);
        this->name = new char[len + 1];
        strcpy(this->name, another.name);
     //4、返回自身
        return *this;
    }
private: int id; char *name; }; int main(void) { Student s1(1, "zhang3"); Student s2 = s1;//拷贝构造 Student s3(2, "li4"); s2 = s3;//赋值操作符 s1.printS();//zhang3 s2.printS();//li4 s3.printS();//li4 return 0; }

案例八:自定义数组类

  =、[]、==、!=、<<、>>等操作符的重载

//MyArray.h

#pragma once
#include <iostream>
using namespace std;
class MyArray
{
public:
    MyArray();
    MyArray(int len);
    MyArray(const MyArray &another);
    ~MyArray();

    void setData(int index, int data);
    int getData(int index);
    int getLen() const;

    MyArray& operator=(const MyArray& another);
    int& operator[](int index) const;
    friend ostream& operator<<(ostream &os, const MyArray &array);
    friend istream& operator >> (istream &is, MyArray &array);
    friend bool operator==(MyArray &array1, MyArray &array2);
    bool operator!=(MyArray &another);

private:
    int len;
    int *space;
};

 

//MyArray.cpp

#include "MyArray.h"

MyArray::MyArray()
{
    cout << "MyArray()..." << endl;
    this->len = 0;
    this->space = NULL;
}

MyArray::MyArray(int len)
{
    if (len <= 0)
    {
        this->len = 0;
        return;
    }
    else
    {
        this->len = len;
        this->space = new int[this->len];
        cout << "MyArray::MyArray(int len)..." << endl;
    }
}

MyArray::MyArray(const MyArray &another)
{
    if (another.len >= 0)
    {
        this->len = another.len;
        
        //深拷贝
        this->space = new int[this->len];
        for (int i = 0;i < this->len;i++)
        {
            this->space[i] = another.space[i];
        }
        cout << "MyArray::MyArray(const MyArray &)..." << endl;
    }
}

MyArray& MyArray::operator=(const MyArray & another)
{
    if (this == &another)
    {
        return *this;
    }

    if (this->space != NULL)
    {
        delete[]this->space;
        this->space = NULL;
        this->len = 0;
    }

    if (another.len >= 0)
    {
        this->len = another.len;

        //深拷贝
        this->space = new int[this->len];
        for (int i = 0;i < this->len;i++)
        {
            this->space[i] = another.space[i];
        }
        cout << "MyArray::operator=(const MyArray &)..." << endl;
    }

    return *this;
}

void MyArray::setData(int index, int data)
{
    if (this->space != NULL)
    {
        this->space[index] = data;
    }
}

int MyArray::getData(int index)
{
    return this->space[index];
}

int MyArray::getLen() const
{
    return this->len;
}


MyArray::~MyArray()
{
    if (this->space != NULL)
    {
        delete[]this->space;
        this->space = NULL;
        len = 0;
        cout << "MyArray::~MyArray()..." << endl;
    }
}

int& MyArray::operator[](int index) const
{
    return this->space[index];
}

ostream& operator<<(ostream &os, const MyArray &array)
{
    os << "遍历整个数组" << endl;
    for (int i = 0;i < array.getLen();i++)
    {
        cout << array[i] << " ";
    }

    os << "调用了<<操作符重载" << endl;

    return os;
}

istream& operator >> (istream &is, MyArray &array)
{
    cout << "请输入" << array.getLen() << "个数" << endl;
    for (int i = 0;i < array.getLen();i++)
    {
        cin >> array[i];
    }
    return is;
}

bool operator==(MyArray &array1, MyArray &array2)
{
    if (array1.len != array2.len)
    {
        return false;
    }
    for (int i = 0;i < array1.len;i++)
    {
        if (array1.space[i] != array2.space[i])
        {
            return false;
        }
    }

    return true;
}

bool MyArray::operator!=(MyArray &another)
{
    return !(*this == another);
}

 

//main.h

#include <iostream> #include "MyArray.h" using namespace std; int main(void) { MyArray array1(10);//开辟10元素的数组 for (int i = 0;i < 10;i++) { array1[i] = i + 10; } cout << "----------" << endl; cout << "array1:" << endl; for (int i=0;i < 10;i++) { //cout << array1.getData(i)<<" "; cout << array1[i] << " "; } cout << endl; MyArray array2 = array1; cout << "array2:" << endl; for (int i = 0;i < array2.getLen();i++) { //cout << array2.getData(i) << " "; cout << array2[i] << " "; } cout << endl; MyArray array3(5); cin >> array3; cout << "array3:" << endl; cout << array3 << endl; cout << endl; if (array3 == array1) { cout << "相等" << endl; } else { cout << "不相等" << endl; } return 0; }

案例九:小括号()重载

#include <iostream>

using namespace std;

class Sqr
{
public:
    Sqr(int a)
    {
        this->a = a;
    }

    int operator()(int value)
    {
        return value*value;
    }

    int operator()(int value1,int value2)
    {
        return value1*value2;
    }

private:
    int a;
};
int main(void)
{
    Sqr s(10);

    int value = s(2);//将一个对象当成一个普通函数来调用,称这种对象是仿函数、伪函数
        //相当于s.operator()(2);
    cout << value << endl;

    value = s(10,20);
    cout << value << endl;

    return 0;
}

案例十:new、delete操作符重载

#include <iostream>
using namespace std;

class A
{
public:
    A()
    {
        cout << "A()..." << endl;
    }
    A(int a)
    {
        cout << "A(int)..." << endl;
        this->a = a;
    }

    //重载的new操作符 依然会触发对象的构造函数
    void * operator new(size_t size)
    {
        cout << "重载了new操作符" << endl;
        return malloc(size);
    }

    void * operator new[](size_t size)
    {
        cout << "重载了new[]操作符" << endl;
        return malloc(size);
    }

    void operator delete(void *p)
    {
        cout << "重载了delete操作符" << endl;
        if (p != NULL)
        {
            free(p);
            p = NULL;
        }
    }

    void operator delete[](void *p)
    {
        cout << "重载了delete[]操作符" << endl;
        if (p != NULL)
        {
            free(p);
            p = NULL;
        }
    }


    ~A()
    {
        cout << "~A()..." << endl;
    }
private:
    int a;
};
int main(void)
{
    A *array_p = new A[5];//array_p->operator new[](sizeof(A[5]));
    delete[] array_p;

    A *ap = new A(5);//ap->operate new(sizeof(A));
    delete ap;

    return 0;
}
//屏幕输出:

重载了new[]操作符
A()...
A()...
A()...
A()...
A()...
~A()...
~A()...
~A()...
~A()...
~A()...
重载了delete[]操作符
重载了new操作符
A(int)...
~A()...
重载了delete操作符

 

未完待续。。。。。。

 

posted @ 2018-10-19 20:57  悦悦的小屋  阅读(893)  评论(0编辑  收藏  举报