运算符重载

我们平常用的+、-、*、/等基本类型,如果我们想用对象也进行如此的操作,就需要我们自定义类并重新实现这样的算法,这就是我们要说的运算符重载,有点像函数重载的味道。

运算符重载不允许我们定义新的运算符也不允许改变它的优先级,它的优先级按照原来本身的优先级进行计算。其中有以下几种运算符不能重载:

  作用域解析运算符   ::

  条件运算符                 ?:

      直接成员访问运算符      .

      sizeof 运算符              sizeof

      解除对指向类成员的指针引用运算符  .*

  运算符的关键定为operator,后面我们常用的运算符号,operator和运算符之间有没有空格都可以,像<、>等中间不用有空格 ,但像特殊的运算符要有空格 ,如operartor new,operator delete等,如果它们之间没有空格,则编译器以为是一个函数名,就会达不到想要的效果,故,没有歧义的情况下我们就不要有空格,但有歧义的时候就把中间加上个空格。

看下面的例子:

  

#include <iostream>
using namespace std;

class CBox
{
public:
CBox(
double lv, double wv, double hv);
CBox();
double Volume() const;

bool operator >(const CBox& box) const; //重载>
bool operator >(const double& Value) const;//重载>
bool operator==(const CBox& box) const;//重载相等符号
private:
double m_length;
double m_width;
double m_height;
};

CBox::CBox(
double lv,double wv, double hv):m_length(lv),m_width(wv),m_height(hv)
{
printf(
"Construct Created!\n");
}

CBox::CBox()
{
m_height
=m_width=m_length=0;
printf(
"Constructed translated params values 0");
}

double CBox::Volume() const
{
return m_length * m_height * m_width;
}


bool CBox::operator>(const CBox& box) const
{
return this->Volume()>box.Volume();
}

bool CBox::operator>(const double& Value) const
{
return this->Volume()>Value;
}

bool CBox::operator==(const CBox& box) const
{
return (this->m_height==box.m_height)&&(this->m_length==box.m_length)&&(this->m_width==box.m_width);
}
void main()
{
CBox box1(
15.5,20.6,3);
CBox box2(
2,5,8.66);
if (box1>box2)
printf(
"box1 is bigger than box2\n");

else
printf(
"box1 is lower than box2\n");

printf(
"the box1 volume: %0.6f\n",box1.Volume());
if (box1>20.5)
printf(
"box1 volume 大于20.5\n");
else
printf(
"box1 volume 小于20.5\n");

CBox box3(
1.2, 2.2, 3.3);
CBox box4(
1.2, 2.2, 3.3);

if (box3==box4)
printf(
"box3等于box4\n");
else
printf(
"box3不等于box4\n");
}

重载符中,第一个const表明实参对象不需要改动它的数据。 &表明类引用,不用再产生一个备份而增大系统开销,最后const表明调用本函数的主体对象的内部数据不让改动,即不影响此对像。

bool operator >(const double& Value) const;是用当前对象和double类型的比较(如:20.0>abox)。而如果我们想比较 一个值和一个对象的大小如何比较?

这个我们可以写一个普通的函数,即不用写在本类中

bool operator>(const double& Value, const CBox& box)

{

   return Value>box.volume();

}

以上数据成员类型为基本的数据类型,如果我们像前些篇章中用到的CShowmsg类,它里面有动态数据成员分配,再用这些可以吗?

重载符=

如:  msg1=msg2等,我们重载=号,因为msg1中有个pmessage指针类型成员,而msg2中也有,就会发现msg1=msg2时,它们的pmessage会指向同一个文本地址,当msg1删除时就会删除这个文本,这时msg2对像是存在的,但其pmessage的地址对像不存在了,这时就会出现错误。

所以,此时,我们可以用以下的重载符=这样处理:

CShowmsg& operator=(const CShowmsg& amsg)
{
delete [] pmessage;
pmessage
=new char[strlen(amsg.pmessage)+1];\
strcpy(
this->pmessage,amsg.pmessage);
return *this;
}

如果有三个CShowmsg对像,msg1=msg2=msg3,这样的情况,如何处理?

因为=号中是从右向左开始的,所以这样是正确的,msg3赋值给msg2,会先把msg2中的pmessage分配的内存删除,然后再建立根据msg3中pmessage 的大小来建msg2中的pmessage.

如果msg1=msg1这样的话又怎么处理呢?即自己赋值给自己。

msg1中有个pmessage,在用重载=时会先把自己的pmessage内存给销毁掉,这时你再赋给自己就不对了,因为pmessage不存在了,就会出错,此时怎么办?

这时我们要做个判断,如果是自己的话就返回自己,什么也做。如下:

CShowmsg& operator=(const CShowmsg& amsg)
{
if (this==&amsg) //检查当前右边的指针地址是否和左值指针一致
return *this;

delete [] pmessage;
pmessage
=new char[strlen(amsg.pmessage)+1];\
strcpy(
this->pmessage,amsg.pmessage);
return *this;
}

以下为全新的例子,运算符等号重载:

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

class CShowmsg
{
private:
char* pmessage;
public:
void Showit() const
{
cout
<<pmessage<<endl;
}

void Reset()
{
char* ptmp=pmessage;
while(*ptmp)
*(ptmp++)='*';

}
CShowmsg
& operator=(const CShowmsg& amsg)
{
if(this==&amsg)
return *this;

delete [] pmessage;
pmessage
=new char[strlen(amsg.pmessage)+1];
strcpy(pmessage,amsg.pmessage);

return *this;
}

CShowmsg(
const char* text="Default message")
{
pmessage
=new char[strlen(text)+1];
strcpy(pmessage,text);
}

~CShowmsg()
{
cout
<<"Destructor Called!\n";
delete [] pmessage;
}
};

void main()
{
CShowmsg msg1(
"The devil takes of his own.");
CShowmsg msg2;
cout
<<"msg2 contains - ";
msg2.Showit();
cout
<<endl;

msg2
=msg1;

cout
<<"msg2 contains - ";
msg2.Showit();
cout
<<endl;

msg1.Reset();
cout
<<"msg1 now contains - ";
msg1.Showit();
cout
<<endl;

cout
<<"msg2 still contains - ";
msg2.Showit();
cout
<<endl;
}

显示结果:

 

从以上例子看出,msg1和msg2两个对象没有一点关系了。

结论:如果需要给类的数据成员动态分配空间,则必须实现赋值去处符。

加减法运算符重载我们在此忽略,相对比较简单。

递增或递减运算符重载即++和--

++和--因在变量前后而不一样,那我们如何重载呢?

看下下面的代码:

#include <iostream>
using namespace std;

class Length
{
private:
double len;
public:
Length
& operator++() //先加再计算
{
len
++;
return *this;
}

const Length operator++(int)//先计算再加
{
return *this;
}

Length
& operator--() //先减再计算
{
len
--;
return *this;
}
const Length operator--(int) //先计算再减
{
return *this;
}
};

void main()
{

}

区分前缀或后缀运算符重载的首要方法是形参列表,前缀形式滑形参,后缀形式有一个int类型的形参。后缀运算符的形参只是为了和前面前缀运算符区分 开来,除此之外它在函数中没用任何用处。

前缀的函数是在用于表达式之前将之递增或递减,因此当前对象在递增或递减之后,我们只需要返回该对象的引用即可。

而在后缀形式中,操作数是在其当前值被表达式使用之后递增或递减的,要实现这点,需要在递增或递减当前对象之前创建当前对象的副本,并在修改过当前对象之后返回新创建的副本对象。

posted on 2011-09-10 16:40  天上星  阅读(686)  评论(1编辑  收藏  举报

导航