正确的重载operator+

  为了得到一串链表或者完成两个对象的累加或合并,经常要重载诸如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返回方式
    ●采用基于重载+=运算符的实行方式
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 请创建一个抽象类DataStructure,该类包括下面的成员变量和成员函数: 1) 一个成员变量len,表示里面的元素个数最大值 2) 构造函数DataStructure(int l),将len初始化为0 3) 虚析构函数~DataStructure() 4) 纯虚函数Output(),输出DataStructure中的数据 5) 纯虚函数Size(),返回DataStructure中的元素个数 2. 请创建DataStructure的一个派生类MyString,该类包括下面的成员变量和成员函数: 1) 一个成员变量char* data,表示里面的数据 2) 构造函数MyString(int max_size),将MyString初始化为空串,最大元素个数为max_size 3) 析构函数~MyString(),释放相应的数据 4) Input()函数,往MyString输入数据 5) 重载operator+=()函数,实现两个字符串的连接 6) 重定义Output()和Size()函数 3. 请创建DataStructure的一个派生类MyStack,该类包括下面的成员变量和成员函数: 1) 一个成员变量int* data,用于里面的数据 2) 一个成员变量int top,表示最上面的元素下标 3) 构造函数MyStack(int max_size),将MyStack初始化为空栈,最大元素个数为max_size 4) 析构函数~MyStack(),释放相应的数据 5) Push_back(int e)函数,往栈里面压入一个数据e 6) 重定义Output()和Size()函数 4. 请编写main函数,测试上面程序的正确性 1) 创建两个MyString的对象str1和str2,分别调用Input函数输入str1和str2,然后分别调用operator+=函数将str2连接到str1的末尾 2) 创建一个MyStack的对象stack,调用Push_back函数输入往stack中输入m(m < max_size)个数据 3) 创建一个长度为3的DataStructure*类型的数组,将其3个元素分别指向str1, str2, stack,然后编写for循环调用Size()和Output()函数输出每个元素的大小和内容。 5. 输入输出样例: 1) 输入样例 A promising techni que for checking reachability 4 12 23 34 45 2) 输出样例 47 A promising technique for checking reachability 29 que for checking reachability 4 12 23 34 45

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值