正确的重载operator+

原创 2001年11月07日 22:34:00

正确的重载operator+ 

(Overloading Operator + the Right Way)

By Danny Kalev, C++ Pro    翻译:周尚延beejoy

为了得到一串链表或者完成两个对象的累加或合并,经常要重载诸如string,date,complex或file等user-define类型的Operator+。然而,就设计而言,正确地重载operator+面临许多挑战。下面的段落中,我将介绍为用户定义类型选择正确的重载operator+的一般性的策略。

考虑下面的表达式:

int x=4+2;

内建的+运算符把两个类型相同的操作数相加然后返回右值6传递给x,因此我们可以说:内建的运算符’+‘是基于二进制的、对称的并且是可交换的操作符,它返回一个与操作数具有相同类型的值。这是一个规则,当你为user-defined类型重载一个运算符时,应该维持相应内建运算符的特性。

为user-defined类型重载operator+是个很普通的事情。不过,由于C++提供了多种实现方式,导致在设计时很容易造成错误,从而对利用标准库组件写出的代码的正确性、执行性能和兼容性造成不利影响。

分析并内建操作符的特性去重载与之相应的user-define运算符。

第一步:选择成员函数或是非成员函数?

我们可以象使用类的成员函数一样使用+、-或是==等二进制操作符,例如:

class String
{
public:
 bool operator==(const String & s); // compare *this and s
};

然而,这种实现方式值得怀疑。在这种情况下,作为内建操作符的副本,重载后的操作符违背了内建操作符具有的对称性,它的两个操作符的类型分别是'const String* const'(隐含的this 参数)和'const String &',这将使得一些STL运算和某一些容器不能正确的处理这些对象。

另一种反其道而行之的方法是,把重载的operator+定义为外部函数,两个参数的类型相同,如下:

String operator + (const String & s1, const String s2);

在这种情况下,类String要定义运算符的重载函数为友元函数:

class String
{
public:
 friend String operator+(const String& s1,const String&s2);
};

第二步:返回值,进退两难的选择

正如前面所述,内建的operator+返回同它的操作符类型相同的右值。不过在caller的堆栈中运行对象将是低效率的,特别是在处理大对象的时候。能不能用返回一个指针或是一个传引用来代替?在这里不行。我们要求变量和返回值的类型要相同,返回指针破坏了这一特性。更糟糕的是,这使得我们不能使用多重连续表达式:

String s1,s2,s3;
String res;
res=s1+s2+s3; //返回不合法的String*

尽管有一个解决办法,也就是另外定义operator+的不同的重载函数, 但这个解决方案没有考虑到另一种情况:当返回的指针指向的是一个动态分配的对象,如果调用者没有清除这个返回的指针,就会导致内存泄漏。所以很明显的,返回String*是个糟糕的想法。

那么可不可以返回String&?同样的,返回的引用必须绑定到一个合法的String。接下来,既然动态分配对象不行,那么第二次我们何不选择返回一个对局部静态变量的引用?是的,静态对象可以解决内存泄漏的问题。不过这仍然有些不可靠。比如在一个多线程程序中,两个线程可能同时调用operator+,这就会导致对string对象的误用。此外,因为静态对象保留上一次调用时的状态,所以我们必须在每次调用operator+前清空这个静态string对象。这样我们得到结论,返回堆栈中的值仍然是最安全并且最简单的解决方案。

第三步:实现

到目前为止一切顺利。在前面我们采用了外部友元函数并且采用by value返回值方式。那么现在该是我们实现重载opertor+函数的时候了。然而又一次,我们面临两种选择:

选择一:Intrusive Concatenation模型

在Intrusive Concatenation模型中,operator+测量函数参数的长度,复制字符串到一个足够地大的缓冲区并且返回结果 ( 为简洁的缘故,我忽略了不常见的情况例如堆过载):

// Option 1: intrusive concatenation
String operator + (const String & s1, const String s2)
{
 int len=s1.size()+s2.size();
 String result;
 result.buf=new char[len+1];
 strcpy(result.buf, s1.buf);
 strcat(result.buf, s2.buf); // concatenate second string
 return result;
}

这个实现能够较好的工作,不过还有更简洁更灵活的基于重载的operator+=的解决方案。

选择二:使用运算符+=

我们使用operator+=来,从而避免对private数据的存取、内存分配以及c函数的使用。

// Option 2: using operator +=
String operator + (const String & s1, const String s2)
{
 String result=s1;
 result+=s2;
 return result;
}

这个实现方法比较容易,而且不会存取string类的非公有数据。并且,我们甚至不需要把它声明为友元函数。operator+=的重载实现留给读者作为练习。

作为重载operator+运算符的最广泛的例子,我们讨论的焦点集中在了自己编写的一个string类。当然,你可以把我介绍的方法和策略应用到任意的user-defined类型上。正确的重载operator+基于以下原则:

●运算符对称性

●返回值与操作符类型相同

采用by value返回方式

●采用基于重载+=运算符的实行方式

(完)

正确的重载operator+

下面的段落中,我将介绍为用户定义类型选择正确的重载operator+的一般性的策略。     第一步:选择成员函数或是非成员函数?    我们可以象使用类的成员函数一样使用+、-或是==等二进制操作符...
  • HEYUTAO007
  • HEYUTAO007
  • 2010年09月04日 15:59
  • 1063

c++之operator运算符重载

转载:http://blog.chinaunix.net/uid-21411227-id-1826759.html 一、实例 1.用成员函数来重载...
  • tankai19880619
  • tankai19880619
  • 2014年06月23日 10:33
  • 1915

编写高质量代码——重载operator=的标准三步走

编写高质量代码——重载operator=的标准三步走
  • u012627502
  • u012627502
  • 2014年06月03日 23:12
  • 1125

operator+单参数和双参数的两种写法

C++运算符重载在自定义类中经常会用到,比如当我们自定义一个点类Point,想对Point类对象进行加减比较判断等操作时,就需要对相应运算符进行重载。   以operator+为例,通常直观的感觉操作...
  • u012043391
  • u012043391
  • 2017年07月27日 09:05
  • 562

【C++语法】关于operator[]重载的注意点

一个类重载operator[]()函数时,要重载operator[]两次,一个是const函数,一个是非const函数。...
  • cly116
  • cly116
  • 2015年08月06日 23:02
  • 938

【C++】String类中的运算符重载

模块化设计: 头文件: #ifndef operator_operator_h #define operator_operator_h #include #include ...
  • Irean_Lau
  • Irean_Lau
  • 2015年06月07日 14:29
  • 6112

C#中的==,!=等符号重载,以及重载等号操作

通过一个实际的例子来介绍。其中重载==,!=,Equal,GetHashCode函数。public class Record{public string[] arr = null;public boo...
  • bingyelee
  • bingyelee
  • 2010年04月18日 10:12
  • 11166

string类中“+”操作符重载(三种形式)

class MyString { public: MyString(char *s)                      //有参构造函数; { str=new char[strl...
  • Lily_whl
  • Lily_whl
  • 2017年03月29日 20:53
  • 264

C++实践参考——复数类中的运算符重载

返回:贺老师课程教学链接【项目1-实现复数类中的运算符重载】(1)请用类的成员函数,定义复数类重载运算符+、-、*、/,使之能用于复数的加减乘除class Complex { public: ...
  • sxhelijian
  • sxhelijian
  • 2015年04月21日 18:33
  • 2664

String系列——运算符重载

本节实现所有运算符的重载。意图很简单,对于运算符重载不清楚的可以查看相关运算符重载的写法。...
  • z702143700
  • z702143700
  • 2015年07月31日 10:26
  • 1309
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:正确的重载operator+
举报原因:
原因补充:

(最多只允许输入30个字)