快疯了的小明同学
在一个月黑风高的晚上,小明正在debug。他已经瞪着自己写的代码三个小时了,硬是没看出来哪里有问题,给助教发消息也不见回音(大半夜的当然没人理他)。看着自己越来越少的头发,看着屏幕上莫名其妙的错误,小明愤怒的抠起了键盘。
![8d269585f978c0e42480a8686c308ca9.png](https://i-blog.csdnimg.cn/blog_migrate/8f53d7d2bf19ed7217b09f3963a11fff.jpeg)
小明正在做一道比较两个字符串的题目,让我们来看看小明写的代码。
#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](https://i-blog.csdnimg.cn/blog_migrate/fa62c64b7c9ab4ac644eecd1cd3214d6.jpeg)
在第二天早上,小明乖乖地把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](https://i-blog.csdnimg.cn/blog_migrate/357b768ede6859547d2bea26d9567343.jpeg)
虽然小明同学因为做不出作业抠键盘而流传千古,但是他现在已经学会了运算符重载,他这么写是有目的的。
对于运算符+=,其在语义上就是对单个对象的更改,定义为类成员函数对私有对象进行更改是合乎逻辑的。而+则在语义上就是使用两个对象得到一个新的对象,甚至可以将其写成常函数,所以定义在类外是合乎逻辑的。那么既然已经实现了+=,用其顺手实现+也是自然而且高效的做法。
所以简单来说:
要更改对象的写成成员函数,类似+=
得到新对象的放在外面,类似+
其中约定+=返回对自己的引用。
自然地,小明又遇到了许多许多问题。
优化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](https://i-blog.csdnimg.cn/blog_migrate/fb0bb13b101ba3a40b59bfef833453c6.jpeg)
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](https://i-blog.csdnimg.cn/blog_migrate/8d60b7becde164b6ebe64be3142a350d.jpeg)