操作符重载

双目操作符

计算类的双目操作符(’+‘和’-’)

  • 表达式的结果是右值。
  • 左右操作数既可以是左值也可以是右值。
  • 两种实现方式:
    • 成员函数形式(左调右参)
      L#R的表达式可以被编译器处理成 L.operator#®的成员函数调用形式,该函数的返回值就是表达式的结果。
    • 全局函数形式(左右操作数都作为参数)
      L#R的表达式也可以被成立成::operator#(L,R)的全局函数调用形式,该函数的返回值就是表达式的结果。
    • 注:使用friend关键字,可以把一个全局函数声明为某个类的友元,友元函数可以访问类中的任何成员。

代码示例

  • complex.cpp
#include <iostream>
using namespace std;
class Complex{
public:
    Complex(int r,int i):m_r(r),m_i(i){}
    void print(void)const{
        cout << m_r << '+' << m_i << 'i'
            << endl;
    }
    //"+"操作符重载函数(成员函数形式)
    //c1 + c2==>c1.operator+(c2)
    //三个const作用
    //1)修饰返回值,禁止对表达式赋值,返回右值
    //2)常引用参数,为了支持常量型右操作数
    //3)常成员函数,为了支持常量型左操作数
    const Complex operator+(
            const Complex& c)const{
        Complex res(m_r+c.m_r,m_i+c.m_i);
        return res;
    }
private:
    int m_r;//实部
    int m_i;//虚部

    //友元,可以访问类中私有成员
    friend const Complex operator-(
        const Complex& l,const Complex& r);
};
//"-"操作符重载函数,全局函数形式
const Complex operator-(
    const Complex& l,const Complex& r){
    Complex res(l.m_r-r.m_r , l.m_i-r.m_i);
    return res;
}

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

    //Complex c3 = c1.operator+(c2);
    Complex c3 = c1 + c2;
    c3.print();//4+6i

    //(c1 + c2) = c3;//应该error

    //c3 = ::operator-(c2,c1)
    c3 = c2 - c1;
    c3.print();//2+2i

    return 0;
}
  • 执行结果
    C++——操作符重载_全局函数

赋值类的双目操作符(+=、-=)

  • 表达式结果是左值,就是左操作数的自身。
  • 左操作数一定是左值,右操作数可以是左值也可以是右值。
  • 两种实现方式:
    • 成员函数形式
      L#R ⇒ L.operator#®
    • 全局函数形式
      L#R ⇒ ::operator#(L,R)

代码示例

  • complex.cpp
#include <iostream>
using namespace std;
class Complex{
public:
    Complex(int r,int i):m_r(r),m_i(i){}
    void print(void)const{
        cout << m_r << '+' << m_i << 'i'
            << endl;
    }
    //"+="成员函数形式
    //c1+=c2==>c1.operator+=(c2)
    Complex& operator+=(const Complex& c){
        m_r += c.m_r;
        m_i += c.m_i;
        return *this;
    }
    //"-="全局函数形式
    //友元函数可以直接定义在类的内部,但本质
    //还是全局函数
    friend Complex& operator-=(
            Complex& l,const Complex& r){
        l.m_r -= r.m_r;
        l.m_i -= r.m_i;
        return l;
    }
private:
    int m_r;//实部
    int m_i;//虚部
};
int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);
    c1 += c2;//c1.operator+=(c2)
    c1.print();//4+6i;
    c1 -= c2;//operator-=(c1,c2)
    c1.print();//1+2i
    return 0;
}
  • 执行结果
    C++——操作符重载_代码示例_02

单目操作符

计算类单目操作符(-(取负)、~(取反))

  • 表达式结果是右值,不能对表达式进行赋值操作
  • 操作数只有一个,可以左值也可以右值
  • 两种实现形式
    • 成员函数形式
      #O ⇒ O.operator#();
    • 全局函数形式
      #O ⇒ ::operator#(O);

代码示例

  • integer.cpp
#include <iostream>
using namespace std;
class Integer{
public:
    Integer(int i):m_i(i){}
    void print(void)const{
        cout << m_i << endl;
    }
    //"-":成员函数形式
    const Integer operator-(void) const {
        Integer res(-m_i);
        return res;
    }
    //"~":全局函数形式(自定义表示乘方)
    friend const Integer operator~(
            const Integer& i){
        Integer res(i.m_i * i.m_i);
        return res;
    }
private:
    int m_i;
};
int main(void)
{
    Integer i(100);
    Integer j = -i;//i.operator-()
    j.print();//-100
    j = ~i;
    j.print();//10000
    return 0;

}
  • 执行结果
    C++——操作符重载_代码示例_03

自增减单目操作符(++、–)

  • 前++、–
    • 表达式的结果是左值,就是操作数自身
    • 操作数一定是左值
    • 两种实现形式
      • 成员函数形式
        #O ⇒ O.operator#();
      • 全局函数形式
        #O ⇒ ::operator#(O);
  • 后++、–
    • 表达式的结果是右值,是操作数自增减前的副本
    • 操作数也一定是左值
    • 两种实现形式
      • 成员函数形式
        O# ⇒ O.operator#(int);
      • 全局函数形式
        O# ⇒ ::operator#(O,int);
    • 注:后缀自增减操作符函数中增加了一个int哑元参数,用于和前缀自增减进行区分。

代码示例

  • integer.cpp
#include <iostream>
using namespace std;
class Integer{
public:
    Integer(int i):m_i(i){}
    void print(void)const{
        cout << m_i << endl;
    }
    //前++:成员函数形式
    Integer& operator++(void){
        ++m_i;
        return *this;
    }
    //前--:全局函数形式
    friend Integer& operator--(Integer& i){
        --i.m_i;
        return i;
    }
    //后++:成员函数形式
    const Integer operator++(int){
        Integer old = *this;
        ++m_i;//++(*this)
        return old;
    }
    //后--:全局函数形式
    friend const Integer operator--(
            Integer& i,int){
        Integer old = i;
        --i.m_i;//--i
        return old;
    }
private:
    int m_i;
};
int main(void)
{
    Integer i(100);
    Integer j = ++i;//i.operator++()
    j.print();//101
    i.print();//101
    j = ++++i;//i.operator++().operator++()
    j.print();//103
    i.print();//103

    j = --i;//operator--(i);
    j.print();//102
    i.print();//102
    j = ----i;
    j.print();//100
    i.print();//100

    j = i++;//i.operator++(0/*哑元*/)
    j.print();//100
    i.print();//101

    j = i--;//operator--(i,0)
    j.print();//101
    i.print();//100

    return 0;
}
  • 执行结果
    C++——操作符重载_操作符_04

插入(输出)和提取(输入)操作符(’<<’ 和 ‘>>’)

功能:实现自定义类型直接的输入和输出

  • 注:只能使用全局函数形式(friend)
  #include <iostream>
  -->ostream cout;
  -->istream cin;

  friend ostream& operator<<(
  		ostream& os,const RIGHT& right){...}
  friend istream& operator>>(
  		istream& is,RIGHT& right){...}

  //全局函数:operator<<(cout,a)
  cout << a;
  cout << c << ...
  //全局函数:operator>>(cin,a)
  cin >> a;
  cin >> c << ...

代码示例

  • io_operator.cpp
#include <iostream>
using namespace std;
class Complex{
public:
    Complex(int r,int i):m_r(r),m_i(i){}
    //<<:只能使用全局函数形式
    friend ostream& operator<<(
            ostream& os,const Complex& c){
        os << c.m_r << '+' << c.m_i << 'i';
        return os;
    }
    //>>:只能使用全局函数形式
    friend istream& operator>>(
            istream& is,Complex& c){
        is >> c.m_r >> c.m_i;
        return is;
    }
private:
    int m_r;//实部
    int m_i;//虚部
};
int main(void)
{
    Complex c1(1,2);
    Complex c2(3,4);
    cout << c1 << endl;
    cout << c1 << ',' << c2 << endl;
    cout << "请输入一个复数" << endl;
    cin >> c1;
    cout << c1 << endl;
    return 0;
}
  • 执行结果
    C++——操作符重载_操作数_05

下标操作符(’[]’)

功能:让一个对象可以像数组一样去使用。

  • 注:非常对象返回左值,常对象返回右值。
	string s = "hello";
	s[0] = 'H';//s.operator[](0) = 'H'; 
	const string s2 = "hello";
	s2[0] = 'H';//error

代码示例

  • array_operator.cpp
#include <iostream>
using namespace std;
//容器类,里面可以存放若干个整形数
class Array{
public:
    //Array(size_t size)
    //  :m_arr(new int[size]),m_size(size){}
    Array(size_t size){
        m_arr = new int[size];
        m_size = size;
    }
    //非常对象调用,返回左值
    int& operator[](size_t i){
        return m_arr[i];
    }
    //常对象调用,返回右值
    const int& operator[](size_t i)const{
        return m_arr[i];
    }
private:
    int* m_arr;
    size_t m_size;
};
int main(void)
{
    Array arr(3);
    arr[0] = 10;//arr.operator[](0)
    arr[1] = 20;
    arr[2] = 30;
    const Array& rarr = arr;
    cout << rarr[0] << endl;
    cout << rarr[1] << endl;
    cout << rarr[2] << endl;
    return 0;
}
  • 执行结果
    C++——操作符重载_操作数_06

函数操作符(’()’)

功能:让对象像函数一样去使用

  • 注:对参数个数、类型和返回值类型没有限制。
	class A{};
	A a;
	a(10,1.23);//a.operator()(10,1.23);	

代码示例

  • func_operator.cpp
#include <iostream>
using namespace std;

class Func{
public:
    double operator()(double x){
        return x*x;
    }
    int operator()(int x,int y){
        return x+y;
    }
};
int main(void)
{
    Func func;
    //func.operator()(3.3)
    cout << func(3.3) << endl;//10.89
    //func.operator()(10,20)
    cout << func(10,20) << endl;//30
    return 0;
}
  • 执行结果
    C++——操作符重载_全局函数_07

new/delete 操作数

  static void* operator new(size_t size){..}
  static void operator delete(void *p){..}

代码示例

  • new.cpp
#include <iostream>
#include <cstdlib>
using namespace std;
class A{
public:
    A(void){
        cout << "A的构造函数" << endl;
    }
    ~A(void){
        cout << "A的析构函数" << endl;
    }
    static void* operator new(size_t size){
        cout << "A::new" << endl;
        void* pv = malloc(size);
        return pv;
    }
    static void operator delete(void *pv){
        cout << "A::delete" << endl;
        free(pv);
    }
};
int main(void)
{
    //1)A* pa=(A*)A::operator new(sizeof(A))
    //2)pa->构造函数
    A* pa = new A;
    
    //1)pa->析构函数
    //2)A::operator delete(pa)
    delete pa;

    return 0;
}
  • 执行结果
    C++——操作符重载_全局函数_08
操作符重载的限制
  • 不是所有的操作符都能重载,以下操作符不能重载:
    • 作用域限定操作符(::)
    • 直接成员访问操作符(.)
    • 直接成员指针解引用操作符(.*)
    • 条件操作符(?:)
    • 字节长度操作符(sizeof)
    • 类型信息操作符(typeid)
  • 如果一个操作符所有操作数都是基本类型,则该操作符无法重载。
  • 操作符重载不会改变编译器预定义的优先级
  • 操作符重载无法改变操作数的个数
  • 无法通过操作符重载发明新的符号
  • 只能使用成员形式不能使用全局形式的操作符(= 、()、->)