C++运算符重载 (含代码)


一 概念介绍

  当运算符作用于自定义的类类型的运算对象时,需要通过运算符重载重新定义该运算的含义。重载的运算符是具有特殊名字的函数:它们的名字由关键字 operator 和其后要定义的运算符号共同组成,如operator+。和其他函数一样,重载的运算符也包含返回类型函数名参数列表以及函数体
  运算符重载按照重载函数定义位置的不同可分为两类:一类是在类内,作为类的成员方法另一种是定义在类外的非成员函数,即普通的全局函数对于类内成员方法:函数仅一个参数,运算符左侧的运算参数是this指代的对象本身,运算符右侧的参数对应成员方法的参数对于非成员函数:函数有两个参数,第一个参数对应运算符左侧参数、第二个参数对应运算符右侧参数非成员函数通常需要访问类的非公有属性,但这在类外是不允许的,因此要么设定非公有属性的get方法,通过函数访问类中的非公有属性;要么将运算符重载函数声明为类的友元函数,友元函数可以访问类中的任何成员属性,前一种方法,增加了函数调用会影响代码效率,故常长采用后者,即友元函数。
  C++中绝大部分运算符是可以重载的,但是有些运算符无法重载。并且有些运算符只能在类内重载,有的只能在类外重载。
  (1) 左移运算符<<右移运算符>>只能在类外重载、即采用非成员函数的方法。
  (2) 赋值运算符=下标运算符[]调用运算符()成员访问箭头运算符->,必须采用类内的成员方法。
  (3) 诸如::.*.?:等运算符无法重载。

  关于运算符重载的几点说明:
  (1) 运算符重载函数中需要注意函数的返回类型:若重载比较运算符,则返回类型是bool型;若重载赋值运算符、复合赋值运算符、输入输出运算符,则返回类型是对象的引用;若重载的是加减乘除等运算符,则返回的是一个对象。
  (2) 重载输入输出运算符时,friend ostream &operator<<(ostream &, const className &);friend istream &operator>>(istream &, className &);这里的第一个参数不论是输入流引用还是输出流引用,都没有用const关键字修饰 (其他运算符重载,参数几乎都带const关键字),原因很简单:那就是在输入或输出时都要向流中传入内容,从而改变流的状态,也就显然不能用const关键字修饰。而重载输出运算符的第二个参数是一个const常量,输入运算符的第二个参数不是const常量,这一点就更好理解了,输出运算符只是输出打印对象的值并不会改变对象的值,故可用const关键字,而输入运算符重载,我们的目的就是将数据读入到这个对象中,从而正确的初始化该对象,所以肯定不能用const关键字修饰。

二 代码演示

  假设我们定义一个Point点类,该类包含x y两个整型变量,分别表示横纵坐标。该点类也可以理解为二维XY笛卡尔坐标系中的一个由(0, 0)原点指向该点的向量。现对该类实现各运算符重载操作,示例代码如下:

#include <iostream>
#include <cmath>
using namespace std;

class Point {
public :
    Point() = default;
    Point(int x, int y) : x(x), y(y) {}
    Point(const Point &obj) : x(obj.x), y(obj.y) {
        cout << "copy constructor" << endl;
    }

    Point &operator=(const Point &a) = default;
    Point operator+(const Point &a) { // 向量对应坐标相加
        Point ret;
        ret.x = this->x + a.x;
        ret.y = this->y + a.y;
        return ret;
    }
    Point &operator+=(const Point &a) { 
        this->x += a.x;
        this->y += a.y;
        return *this;
    }
    Point &operator()(const int val) {  // 假设调用运算符操作为横纵坐标都加上val值
        this->x += val;
        this->y += val;
        return *this;
    }
    int operator[](const string &name) {  // 根据下标获取对应坐标
        if (name == "x") return this->x;
        if (name == "y") return this->y;
        return -1;
    }
    bool operator<(const Point &a) {  // 比较两向量的长度
        double dis1 = pow((pow(this->x, 2) + pow(this->y, 2)), 0.5);
        double dis2 = pow((pow(a.x, 2) + pow(a.y, 2)), 0.5);
        return dis1 < dis2;
    }

    friend ostream &operator<<(ostream &, const Point &);
    friend istream &operator>>(istream &, Point &);
    friend Point operator-(const Point &, const Point &);

private :
    int x, y;
};


ostream &operator<<(ostream &os, const Point &a) {
    os << "value of this point: (" << a.x << ", " << a.y << ")";
    return os;
}
istream &operator>>(istream &is, Point &a) {
    is >> a.x >> a.y;
    if (!is) { a = Point(); }
    return is;
}
Point operator-(const Point &a, const Point &b) {
    Point ret;
    ret.x = a.x - b.x;
    ret.y = a.y - b.y;
    return ret;
}

int main() {
    Point a(1, 2);
    cout << "a: " << a << endl;
    Point b;
    cin >> b;
    cout << "b: " << b << endl;
    Point c = a - b;
    cout << "c: " << c << endl;
    a += b;
    cout << "a: " << a << endl;

    if (a < c) {
        cout << "len(a) < len(c)" << endl;
    } else {
        cout << "len(a) >= len(c)" << endl;
    }

    cout << "(" << a["x"] << ", " << a["y"] << ")" << endl;
    cout << "a: " << a << endl;
    a(5);
    cout << "a: " << a << endl;

    return 0;
}

/* 代码输出
a: value of this point: (1, 2)
-5 -6  // 输入b对象
b: value of this point: (-5, -6)
c: value of this point: (6, 8)
a: value of this point: (-4, -4)
len(a) < len(c)
(-4, -4)
a: value of this point: (-4, -4)
a: value of this point: (1, 1)
*/

  如上图所示,Point类重载了:赋值运算符 =加法运算符 +复合赋值运算符 +=调用运算符 ()下标运算符 []小于运算符<左移运算符 <<右移运算符 >>减法运算符-,其中后三者在类外实现,即采用非成员函数实现,剩下的在类内,采用成员方法实现。在运算符重载函数中,值得注意的是函数的返回值类型,特别是何时返回值value,何时返回引用&,千万莫要混淆。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值