在C++中不可重载的运算符有:
::
sizeof
? :
:
.->
可重载的运算符有:
=
==
!=
*
()
[]
+
*
new
delete
其中注意一下:C++中new和delete与C语言中malloc和free不一样。C语言中malloc和free市库函数;在C++中new和delete是运算符;在使用new时相当于默认使用构造函数+malloc,在使用delete时相当于默认使用析构函数+free.
我们在刚开始学面向对象时就学习了C++中的六个默认构造函数,其中有一个就是赋值运算符重载函数,它重载的是赋值运算符,想必大家都知道了,那么这篇博文就先对赋值运算符重载函数具体的要求和写法做以总结。其次再举例说明其他的重载函数。
当我们给出一个类的声明时,写赋值运算符函数要考虑三个方面:
1、传参:
1.1:对于操作运算符重载函数要传的参数可以是引用也可以不是引用。但考虑到传引用时不用生成一个临时对象,不用调用拷贝构造函数,效率高,我们选择传引用。
1.2:考虑到修饰的形参不能被修改且要能接收隐式产生的临时量,我们要传常引用。
2、返回值:
2.1:考虑到要能进行连续赋值,我们要传引用,因为如果不传引用的话,传回去第二次赋的值就给了临时量,而且表达式结束时临时量被销毁,不能做到连续赋值。
2.2:函数结束前返回实例自身的引用,既*this。
3、函数体:
3.1:判断自赋值,如果自赋值,直接返回。
3.2:释放自身的资源,防止内存泄漏。
3.3:开辟新的资源,防止同一块内存区域被释放多次,导致程序奔溃。
有了以上的掌握,接下来借助一个类CString我们书写+ [] == != << >>运算符重载函数#include<iostream>
#include<string>
using namespace std;
class CString
{
public:
CString()
{
cout<<"CString()"<<endl;
mpstring=new char[1];
cursize=0;
}
CString(char* str)
{
cout<<"CString(char*)"<<endl;
mpstring=new char[strlen(str)+1];
strcpy(mpstring,str);
cursize=strlen(str);
}
~CString()
{
cout<<"~CString()"<<endl;
delete[] mpstring;
mpstring=NULL;
}
CString& operator=(const CString& rhs)
{
cout<<"operator="<<endl;
/*
if(this == &rhs)
{
return *this;
}
delete[] mpstring;
mpstring=new char[strlen(rhs.mpstring)+1];
strcpy(mpstring,rhs.mpstring);
cursize=rhs.cursize;
return *this;*/
if(this!=&rhs)
{
delete[] mpstring;
mpstring=new char[strlen(rhs.mpstring)+1];
strcpy(mpstring,rhs.mpstring);
cursize=rhs.cursize;
}
return *this;
}
bool operator==(const CString& rhs)
{
cout<<"operator=="<<endl;
return strcmp(mpstring,rhs.mpstring)==0;
}
bool operator!=(const CString& rhs)
{
cout<<"operator!="<<endl;
//return strcmp(mpstring,rhs.mpstring)!=0;//方法一
return !(*this==rhs);//方法二
}
char& operator[](int index)
{
cout<<"operator[]"<<endl;
return mpstring[index];
}
private:
char* mpstring;
int cursize;
friend CString operator+(const CString&,const CString&);
friend ostream& operator<<(ostream&,const CString&);
friend istream& operator>>(istream&,CString&);
};
CString operator+(const CString& lhs,const CString& rhs)
/*必须写在类外,因为要满足所有情况,
比如:CString str3=str1+"world";或者CString str4="Hello"+str1;*/
{
cout<<"operator+"<<endl;
int lhs_len=strlen(lhs.mpstring);
int rhs_len=strlen(rhs.mpstring);
int len=lhs_len+rhs_len+1;
//char* str=new char[len];
char str[20]="";
strcat(str,rhs.mpstring);
strcat(str,rhs.mpstring);
//CString obj(str);
return CString(str);
}
ostream& operator<<(ostream& out,const CString& rhs)
{
cout<<"operator<<"<<endl;
out<<rhs.mpstring<<"";
return out;
}
istream& operator>>(istream& in,CString& rhs)//输入流要修改,所以不用加const
{
cout<<"operator>>"<<endl;
char p[20];
in>>p;
if(in)
{
delete[] rhs.mpstring;
rhs.mpstring=new char[strlen(p)+1];
strcpy(rhs.mpstring,p);
rhs.cursize=strlen(p);
}
return in;
}
int main()
{
CString str1;
CString str2("hello");
CString str3=str2+"world";
CString str4="hello"+str2;
str3=str4;
if(str2!=str4)
{
cout<<str4<<endl;
}
if(str3==str4)
{
cout<<str3<<endl;
cout<<str3[0]<<endl;
}
cin>>str1;
cout<<str1<<endl;
return 0;
}
运行结果:
总结:
(1)、加法运算符重载函数一定要写在类外,因为传进去的第一个参数不一定是一个对象(没有this指针)。
(2)、<<或者>>运算符重载也要写在类外,因为<<和>>都是由缓冲区的一个实例来调用,不是类实例出的对象来调用。
(3)、对于返回值是不是要返回引用只需要判断返回之后是否要被修改,如果要修改传引用,否则不用传引用。