一进列运算符的参数不对_C++运算符重载

快疯了的小明同学

在一个月黑风高的晚上,小明正在debug。他已经瞪着自己写的代码三个小时了,硬是没看出来哪里有问题,给助教发消息也不见回音(大半夜的当然没人理他)。看着自己越来越少的头发,看着屏幕上莫名其妙的错误,小明愤怒的抠起了键盘。

8d269585f978c0e42480a8686c308ca9.png

小明正在做一道比较两个字符串的题目,让我们来看看小明写的代码。

#include

using namespace std;

int main()

{

        char s1[20];

        char s2[20];

        cin>>s1>>s2;

        if(s1==s2)

                cout<

        else

                cout<

        return 0;

}

小明不论输入什么,这个程序的输出总是not same,从来都没有变过,小明甚至怀疑他写了一个复读机。

乍一看,程序结构清晰且合理,看起来没有什么问题。但是等下,s1==s2是不是有点不对?

小明采用的是字符数组储存字符串,但是光光一个s1,调用的是s1的地址,两个字符串的地址自然不同,小明的确写了一个复读机出来。

7fd1d1d227ba66bb8f76d8a8bdb63511.png

在第二天早上,小明乖乖地把s1==s2改成了!strcmp(s1,s2),成功地完成了自己的作业。

不过等下,我们上天入地无所不能的小明会这么没有理想吗?他早已暗下决心要让自己s1==s2的代码顺利运行。于是,他就开始了运算符重载的学习。

什么是运算符重载

“您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。”

以上就是运算符重载的介绍,但是人们并没有耐心去看那种难于理解的介绍(几乎是显然的),我们来把以上内容翻译成人话。

a+b

等价于

operator+(a,b)

或者

a.operator+(b)

+号就是一个函数,所以当然是可以重载的。我们可以对每一种自定义类型重载一个+号,当然-号和其他大多数运算符也是一样。

你以为我在第一层,实际上我在第二层(一看就是老千层饼了)。

什么是运算符重载

第二天小明的复变函数开课了,小明就打算自己编写一个复数类,并且重载常见的运算符。我们就拿小明的代码作为我们的例子。

class complex

{

        double re,im;

public:

        complex(double r,doubel i):re(r),im(i){}

        complex& operator+=(complex a);

};

complex& complex::operator+=(complex a)

{

        re+=a.re;

        im+=a.im;

        return *this;

}

operator+(complex a,complex b)

{

        complex r=a;

        return r+=b;

}

相信这时候小朋友们的头上都冒出了大大的问号,小明这是干啥呢?为什么+=是成员函数,而+就不是成员函数了呢?为什么要用实现+,这不是迷惑吗?

142cc88cdfab42ec2e5c5b065d8f6cc6.png

虽然小明同学因为做不出作业抠键盘而流传千古,但是他现在已经学会了运算符重载,他这么写是有目的的。

对于运算符+=,其在语义上就是对单个对象的更改,定义为类成员函数对私有对象进行更改是合乎逻辑的。而+则在语义上就是使用两个对象得到一个新的对象,甚至可以将其写成常函数,所以定义在类外是合乎逻辑的。那么既然已经实现了+=,用其顺手实现+也是自然而且高效的做法。

所以简单来说:

  1. 要更改对象的写成成员函数,类似+=

  2. 得到新对象的放在外面,类似+

其中约定+=返回对自己的引用。

自然地,小明又遇到了许多许多问题。

优化complex类设计

在定义了以上的内容后,小明高兴地开始了debug,不出所料,他又开始抠键盘了。让我们来看看他的代码。

complex c=complex(1,2)+3;

一个错误蹦了出来,小明本以为会得到(4,2),但他什么都没有得到,除了几个error。

这是因为int或者double类型并没有转换成complex类型的构造函数,那还不简单吗,加上就可以了。将构造函数改为

complex(double r=0,doubel i=0):re(r),im(i){}

这样一来就可以简单的将3转化为(3,0)了。同时,小明还避免了写三个长得很像的重载函数

complex operator+(complex,complex),

complex operator+(double,complex),

complex operator+(complex,double) 。

之后,小明还加入了获得实部和虚部的接口。

double real() const { return re; }

double imag() const { return im; }

必不可少的乘法运算。

complex& complex::operator*=

        (const complex& a)

{

        double temp_re = re*a.re-im*a.im;

        im = im*a.re+re*a.im;

        re = temp_re;

        return *this;

}

complex operator*(const complex& a, 

        const complex& b)

{

        complex r = a;

        return r *= b;

}

还有他心心念念的比较运算符。

bool operator==(const complex& a, 

        const complex& b)

{

        return a.real() == b.real() &&

             a.imag() == b.imag();

}

或许,他将来还可以定义<

字符串类

在小明学会了运算符重载之后,他自己写了一个字符串类。他今后终于可以使用str1==str2了,他感觉自己是机房里最靓的仔。我们在这里贴出string类的代码。

be0e0e8af9fa3b5543cd83b697bb751a.png

class cstr

//注:以下均不提供范围检查

{

char* p;

public:

cstr(int n) { p = new char[n]; }

cstr(const char* s) {

        p = new char[strlen(s)];strcpy(p, s);}

cstr(const cstr& a) { 

        p = new char[strlen(a.p)]; strcpy(p, a.p); }

~cstr() { delete[] p; }

cstr& operator+=(const cstr& a);

char& operator[](int n) { return p[n]; }

char operator[](int n) const { return p[n]; }

bool operator==(const cstr& a){

        return !strcmp(p, a.p);}

void print() { cout << p << endl; }

};

cstr& cstr::operator+=(const cstr& a)

{

        char* pt = p + strlen(p);

        strcpy(pt, a.p);

        return *this;

}

cstr operator+(const cstr& a,const cstr& b)

{

        cstr r = a;

        return r += b;

}

以上代码为小明自己所写,如有错误或不明了之处,欢迎大家在评论区交流讨论。

附录:

1.一个不完整的complex类

class complex

{

        double re, im;

public:

        complex(double r=0, double i=0) :re(r), im(i) {}

        complex& operator+=(const complex& a);

        complex& operator*=(const complex& a);

        double real() const { return re; }

        double imag() const { return im; }

};

complex& complex::operator+=(const complex& a)

{

        re += a.re;

        im += a.im;

        return *this;

}

complex& complex::operator*=(const complex& a)

{

        double temp_re = re*a.re-im*a.im;

        im = im*a.re+re*a.im;

        re = temp_re;

        return *this;

}

complex operator+(const complex& a,const complex& b)

{

        complex r = a;

        return r += b;

}

complex operator*(const complex& a, const complex& b)

{

        complex r = a;

        return r *= b;

}

bool operator==(const complex& a, const complex& b)

{

        return a.real() == b.real() && a.imag() == b.imag();

}

2.参考文献

Bjarne Stroustrup. C++程序设计语言. 运算符重载.

作者:梅树尧

审核:刘政宁

指导老师:李超

30beea5fe3aeb77872253fa5f80f1228.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值