C++运算符重载

运算符重载

运算符重载背景:
c++语言中,运算符可直接拿来进行整数、小数等的运算,但这些运算对象都是c++语言中的标准对象,这种情况能满足我们大多数的应用场景,但是,面对我们自定义的对象,运算符不能直接拿来使用,例如自己构造一个复数的类,默认情况下,c++语言不支持复数运算,因此我们需要将运算符重载,使它们能够满足我们自定义的对象的运算。运算符重载的实质是函数重载,它提供了C++的可扩展性,也是C++最吸引人的特性之一。

运算符重载规则

  • C++几乎可以重载全部的运算符,而且只能够c++中已经有的
    • 不能重载的运算符:“.”,“.*”,“::”,“?:”
  • 重载之后运算符的优先级和结合性都不会改变
  • 运算符重载是针对新数据类型的实际需要,对原有运算符进行适当改造。
    • 例如
    • 使复数类的对象可以使用“+”运算符实现加法
    • 使时钟类对象可以用“++”运算符实现时间增加1秒

重载的两种形式

  • 重载为类的非静态成员函数
  • 重载为非成员函数

双目运算符重载为成员函数

重载为类成员的运算符函数定义形式:

函数类型 operator 运算符(形参)
{
    ·····
}
参数个数=源操作数个数-1(后置++--除外)

当运算符重载为类的成员函数时,函数的参数个数比原来的操作数要少一个(后置单目运算符除外),这是因为成员函数用this指针隐式地访问了类的一个对象,它充当了运算符函数最左边的操作数。


双目运算符重载规则(重载为类的非静态成员函数)

  • 如果要重载B为类成员函数,使之能够实现表达式oprd1 B oprd2
    其中oprd1A类对象,则B应被重载为A类的成员函数,形参类
    型应该是oprd2所属的类型。
  • 经重载后,表达式oprd1 B oprd2相当于 oprd1. operator B(oprd2)

举一个例子实现复数类加减法运算重载为成员函数

  • 要求
    • +-运算重载为复数类的成员函数
  • 规则
    • 实部和虚部分别相加减
  • 操作数
    • 两个操作数都是复数类对象

示例代码:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
    //运算符 + 重载成员函数
    Complex operator +(const Complex &c1)const;
    //运算符 - 重载成员函数
    Complex operator -(const Complex &c2)const;
    void display() const; // 输出复数
private:
    double real; // 复数实部
    double imag;//复数虚部
};

Complex Complex:: operator +(const Complex &c1)const {
    return Complex(real + c1.real, imag + c1.imag);
}
Complex Complex::operator - (const Complex &c2)const {
    return Complex(real - c2.real, imag - c2.imag);
}
void Complex::display()const {
    cout << "("<<real << "," << imag << ")" << endl;
}
int main(void)
{
    Complex c1(4, 5), c2(2, 10), c3;
    cout << "c1="; c1.display();
    cout << "c2="; c2.display();
    c3 = c1 - c2;//使用重载运算符完成复数减法
    cout << "c3=c1-c2="; c3.display();
    c3 = c1 + c2;//使用重载运算符完成复数加法
    cout << "c3=c1+c2="; c3.display();
}

代码运行结果:

c1=(4,5)
c2=(2,10)
c3=c1-c2=(2,-5)
c3=c1+c2=(6,15)
请按任意键继续. . .

单目运算符重载为成员函数

因为++ --参与运算时前置后置属于两种不同计算行为,在类内声明时函数名相同,怎样区分他们的功能呢?就是利用重载函数的区分原则即参数不同,下面详细介绍具体规则

前置单目运算符重载规则

  • 如果重载函数U为类沉管函数,使之能够实现表达式U oprd,其中oprdA类对象,则U应被重载为A类成员函数,无形参。
  • 经重载后
    表达式U oprd相当于oprd.operator U()

后置单目运算符重载规则

  • 如果要重载++--为类的成员函数,使之能够实现表达式oprd++oprd--,其中oprdA类对象,则++--应被重载为A类的成员函数,且具有一个int类型形参
  • 经重载后,表达式oprd++相当于oprd.operator ++(0)

举一个时钟类例子来说明具体用法:

#include <iostream>
using namespace std;
class Clock {
public:
    Clock(int hour = 0, int min = 0, int sec = 0);
    void Show_Time();
    //前置单目运算符重载
    Clock operator ++();
    //后置单目运算符重载
    Clock operator ++(int);
private:
    int hour, min, sec;
};
Clock::Clock(int hour, int min, int sec) {
    if (0 <= hour && hour < 24 && 0 <= min && min < 60 && 0 <= sec && sec < 60)
    {
        this->hour = hour;
        this->min = min;
        this->sec = sec;
    }
    else {
        cout << "Time Err" << endl;
    }
}
void Clock::Show_Time() {
    cout << hour << ":" << min << ":" << sec << endl;
}
Clock Clock::operator ++() {
    sec++;
    if (sec >= 60) {
        sec -= 60;
        min++;
        if (min >= 60) {
            min -= 60;
            hour = (hour + 1) % 24;
        }
    }
    return *this;
}
Clock Clock::operator ++(int) {
    Clock old = *this;
    ++(*this);
    return old;
}
int main(void)
{
    Clock myClock(23, 59, 59);
    cout << "first time: ";
    myClock.Show_Time();
    cout << "++myClock time: ";
    (++myClock).Show_Time();
    cout << "myClock++ time: ";
    (myClock++).Show_Time();
    cout << "after myClock++ time: ";
    myClock.Show_Time();
    return 0;
}

代码运行结果:

first time: 23:59:59
++myClock time: 0:0:0
myClock++ time: 0:0:0
after myClock++ time: 0:0:1
请按任意键继续. . .

运算符重载为非成员函数

应用场景

  • 左值为非类成员,参与与类的运算(实数与复数类的运算)
  • 左值为类成员,但该类属于类库中的成员,或者我们没有办法为类添加重载函数的情况

运算符重载为非成员函数的规则

  • 函数的形参依自左至右次序排列的各操作数
  • 重载为非成员函数时
    • 参数个数=原操作数个数(后置++ --除外)
    • 至少有一个自定义类型的参数
  • 后置单目运算符++--的重载函数,形参列表中要增加一个int,但不必写形参名。
  • 如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元
  • 双目运算符B重载后,表达式oprd1 B oprd2等同于operator B(oprd1,oprd2)
  • 前置单目运算符B重载后,表达式B oprd等同于operator B(oprd)
  • 后置单目运算符++ --重载后表达式oprd B相当于operator B(oprd,0)

例子重载Complex的加减法和“<<”运算符为非成员函数

  • +-(双目)重载为非成员函数,并将其声明为复数类的友元,两个操作数都是复数类的常引用
  • <<(双目)重载为 非成员函数,并将其声明为复数类的友元,它的左操作数是std::ostream引用,有操作数为复数类的常引用,返回std::ostream引用,用以支持下面形式的输出:cout<<a<<b;
    该输出调用的是:
    operator<<(operator<<(cout,a),b)

代码如下:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
    //运算符 + 重载成员函数
    friend Complex operator +(const Complex &c1,const Complex &c2);
    //运算符 - 重载成员函数
    friend Complex operator -(const Complex &c1, const Complex &c2);
    friend ostream& operator <<(ostream &out,const Complex &c);
    void display() const; // 输出复数
private:
    double real; // 复数实部
    double imag;//复数虚部
};

Complex  operator +(const Complex &c1, const Complex &c2) {
    return Complex(c1.real+c2.real, c1.imag + c2.imag);
}
Complex operator - (const Complex &c1, const Complex &c2){
    return Complex(c1.real - c2.real, c1.imag - c2.imag);
}
ostream& operator <<(ostream &out, const Complex &c) {
    out << "(" << c.real << "," << c.imag << ")";
    return out;
}
void Complex::display()const {
    cout << "(" << real << "," << imag << ")" << endl;
}
int main(void)
{
    Complex c1(4, 5), c2(2, 10), c3;
    cout << "c1="; c1.display();
    cout << "c2="; c2.display();
    c3 = c1 - c2;//使用重载运算符完成复数减法
    cout << "c3=c1-c2="; c3.display();
    c3 = c1 + c2;//使用重载运算符完成复数加法
    cout << "c3=c1+c2="; c3.display();
    cout << "c3:" << c3 << endl;
    return 0;
}

代码运行结果:

c1=(4,5)
c2=(2,10)
c3=c1-c2=(2,-5)
c3=c1+c2=(6,15)
c3:(6,15)
请按任意键继续. . .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值