10.操作符重载

1.四则运算符重载

设计一个数偶类,定义专用的四则运算

#include <iostream>
using namespace std;
class Couple
{
public:
    Couple(int a = 0, int b = 0):_a(a),_b(b){}
    Couple operator+(const Couple &c);
    //friend Couple operator+(const Couple &c1,const Couple &c2);
    Couple operator-(const Couple &c);
    Couple operator*(const Couple &c);
    Couple operator/(const Couple &c);
    void print()
    {
        cout<<"a:"<<_a<<"\tb:"<<_b<<endl;
    }
private:
    int _a,_b;
};
Couple Couple::operator+(const Couple &c)
{
    Couple _t(this->_a + c._a, this->_b + c._b);
    return _t;
}
/*
Couple operator+(const Couple &c1,const Couple &c2)
{
	Couple _t(c1.a + c2.a, c1.b + c2.b);
	return -t;
}
*/
Couple Couple::operator-(const Couple &c)
{
    Couple _t(this->_a - c._a, this->_b - c._b);
    return _t;
}
Couple Couple::operator*(const Couple &c)
{
    Couple _t(this->_a * c._a, this->_b * c._b);
    return _t;
}
Couple Couple::operator/(const Couple &c)
{
    Couple _t(this->_a / c._a, this->_b / c._b);
    return _t;
}

int main()
{
    Couple a(1,2),b(3,4),c,d;
    c = a + b;  //等价于c = a.operator+(b) ==> c(4,6)
    d = c / a;  //等价于d = c.operator/(b) ==> d(4,3)
    c.print();  //a:4  b:6
    d.print();  //a:4  b:3
    return 0;
}

涉及到的问题

  1. 参数必须是Couple类对象的常引用吗?

    可以不使用引用,但是值传递会产生对象拷贝动作,降低效率

    可以不是常引用,但无法限制函数内部对参数的修改

    可以使用指针,但与常规数学公式使用方式不符,

  2. 返回值必须是Couple类的对象吗?返回引用是否可行?

    可以返回引用,但必须是全局对象或通过参数传递进去的Couple对象的引用,不能引用函数内部的局部变量

    不建议使用引用类型的返回值

    需要将右操作数累加到左操作数上并返回左操作数时,此时应该重载加赋、减赋、乘赋、除赋、余赋等操作符

  3. 四则运算符必须重载为成员函数吗?

    可以重载为类的友元函数或普通函数。注意:普通函数无法访问类的私有成员

    建议重载为友元函数。好处:显式具有双操作数,且格式一致;操作不局限于当前对象本身,且不要求左操作数必须为本类的对象。坏处:显式具有双操作数,不能省略左操作数

2.关系运算符重载

为数偶类定义专门的关系操作符

class Couple
{
public:
	Couple(int a = 0, b = 0):_a(),_b(){}
    friend bool operator==(const Couple &c1,const Couple &c2);
    friend bool operator!=(const Couple &c1,const Couple &c2);
private:
	int _a,_b;    
};
bool operator==(const Couple &c1,const Couple &c2)
{
    return (c1._a==c2._a)&&(c1.b==c2._b);
}
bool operator!=(const Couple &c1,const Couple &c2)
{
    return (c1._a!=c2._a)||(c1._b!=c2._b);
}
int main()
{
    Couple a(1,2),b(2,1),c(1,2);
    cout<<“a=b?”<<char(a==b?'y':'n')<<endl;
    cout<<"a!=b"<<char(a!=b?'y':'n'<<endl;
}

3.下标操作符重载

下标操作符重载的场合于目的

  • 如果对象具有数组成员,且该成员为主要成员,可以重载下标操作符
  • 目的:以允许在对象上通过数组下标访问该数组成员的元素

下标操作符必须重载两个版本

  • 常函数版本用于处理常量

数组下标越界错误

  • 可以在重载函数中处理数组下标越界错误,或使用异常处理机制
class Couple
{
public:
	Couple(int a = 0,b = 0){_a[0] = a,_a[1] = b;}
    int& operator[](int index);
    const int& opertor[](int index) const;
private:
    int _a[2];
};
int& Couple::operator[](int index)
{
    if(index < 0 || index > 1)
        throw std::out_of_range("The index is out of range.");
    return _a[index];
}
const int& operator[](int index) const
{
   if(index < 0 || index > 1)
        throw std::out_of_range("The index is out of range.");
    return _a[index]; 
}
int main()
{
    Couple a(1,2),b(3,4);
    cin>>a[0]>>a[1];
    cout<<b[0]<<" "<<b[1];
    return 0;
}

4.赋值操作符重载

赋值操作符重载的一般形式

class Couple
{
public:
    Couple(int a = 0,int b = 0):_a(a),_b(b){}
    Couple(const Couple& c):_a(c._a),_b(c._b){}
    Couple& operator=(const Couple& c);
private:
    int _a,_b;
};
Couple& Couple::operator=(const Couple& c)
{
    if(*this == c)
        return *this;
    _a = c._a,_b = c._b;
    return *this;
}
int main()
{
    Couple a(1,2),b(3,4);
    a = b;
    cout<<a<<endl;
    return 0;
}

复合赋值操作符重载

class Couple
{
public:
    Couple(int a = 0,int b = 0):_a(a),_b(b){}
    Couple(const Couple& c):_a(c._a),_b(c._b){}
    Couple& operator+=(const Couple& c);
    Couple& operator*=(const Couple& k);
    Couple& operator*=(const int& k);
    void Print(){cout<<_a<<" "<<_b<<endl;}
private:
    int _a,_b;
};
Couple& Couple::operator+=(const Couple& c)
{
    _a += c._a,_b += c._b;
    return *this;
}
Couple& Couple::operator*=(const Couple& k)
{
    _a *= k._a,_b *= k._b;
    return *this;
}
Couple& Couple::operator*=(const int& k)
{
    _a *= k,_b *= k;
    return *this;
}
int main()
{
    Couple a(1,2),b(3,4);
    a += b;
    a.Print();
    a *= 2;
    a.Print();
    return 0;
}

赋值构造与拷贝构造

  • 赋值也是构造

  • 拷贝、赋值与析构三位一体,一般同时出现

    --缺省赋值构造与拷贝构造为浅拷贝

    --如果对象没有指针成员,缺省行为即可满足要求,无需实现或重载这三个函数

    --如果对象有指针成员,一般需要重载这三个函数

浅拷贝与深拷贝

移动语义(C++11)

5.流操作符重载

为数偶类定义专用的流操作符

class Couple
{
public:
    Couple(int a = 0, int b = 0):_a(a),_b(b){}
    //必须使用此格式,以与流的连续读写特性保持一致
    friend ostream& operator<<(ostream& os,const Couple& c);
    friend istream& operator>>(istream& is,Couple& c);
private:
    int _a,_b;
};
//注意:此处实现的流输入输出格式不统一
ostream& operator<<(ostream& os,const Couple& c)
{
    os<<"("<<c._a<<","<<c._b<<"("<<endl;
    return os;
}
istream& operator>>(istream& is,Couple& c)
{
    is>>c._a>>c._b;
    return is;
}
int main()
{
    Couple a(1,2),b;
    cin>>b;
    cout<<a<<b<<endl;
    return 0;
}

6.操作符重载总结

哪些操作符可以重载?

  • 不可重载操作符:“::” "?:" "." ".*" "sizeof" "#" "##" "typeid"
  • 其他操作符都可重载

操作符重载原则

  • 只能使用已有的操作符,不能创建新的操作符
  • 操作符也是函数,重载遵循函数重载原则
  • 重载的操作符不能改变优先级与结合性,也不能改变操作数个数及语法结构
  • 重载的操作符不能改变其用于内部类型对象的含义,它只能和用户自定义类型的对象一起使用,或者用于用户自定义类型的对象和内部类型的对象混合使用
  • 重载的操作符在功能上应与原有功能一致,即保持一致的语义
posted @ 2020-10-21 20:27  bear-Zhao  阅读(92)  评论(0编辑  收藏  举报