复合赋值和添加运算符重载

时间:2012-04-30 00:02:51

标签: c++ string operator-overloading compound-assignment

我需要帮助解决下面提到的两个运算符重载函数。我不确定如何在不实际使用函数定义中的赋值的情况下实现它。

我的.cpp文件中的operator +代码:

MyString& MyString::operator +(const MyString& rhs)
{
  delete [] String;
  String = new char[rhs.Size];
  Size = rhs.Size;
  // needs to be a loop for cascading + 
  // so that String1=String2+String3+String4 will work
  for(int i = 0; i < rhs.Size+1 ; i++)
  {
    //  String[i] + rhs.String[i]; ???
  }
  return *this;
}

.cpp文件中的+ =运算符代码:

MyString& MyString::operator+=(const MyString& rhs)
{
  delete [] String;
  String = new char[rhs.Size];
  String = String + rhs.String;
  return *this;
}

来自main.cpp的电话:

 String1 = String2 + String3 + String4;
 String1.Print ();

 String2 += String3;
 String2.Print ();

我知道我的.cpp文件代码有误,有些见解会很棒!

2 个答案:

答案 0 :(得分:3)

惯用法是在operator+=中实现功能,然后使用它来实现operator+。假设对于初学者而不是operator+=正确实施,那么operator+可以作为自由函数轻松实现:

MyString operator+( MyString lhs, MyString const & rhs ) {
   lhs += rhs;
   return lhs;
}

注意:第一个参数是按值传递的,因此它是我们可以通过operator+=修改的原始文件的副本。您可能会发现其他一些有用的提示here

现在回到实现operator+=,您应该首先理解的是您需要执行的操作是什么:您需要分配更长的缓冲区,从旧缓冲区复制,附加{{1字符串,交换旧缓冲区和新缓冲区(包含结果)并释放旧缓冲区。操作的顺序很重要,如果您在复制之前释放旧内容(正如您所做的那样),那么您将无法再从中复制。

rhs

[1]:分配新缓冲区并复制到它。请注意,在此特定情况下,代码正确,因为函数中的其余指令都不会引发异常。如果不是这种情况,则应通过RAII管理新缓冲区,以确保至少最小的异常安全。

[2]:假设作为类型// Rough approach MyString& operator+=( MyString const & rhs ) { char * new_buffer = new char[ Size + rhs.size + 1]; // [1] std::copy_n( String, Size, new_buffer ); std::copy_n( rhs.String, rhs.Size + 1, new_buffer+Size ); // [2] swap(String, new_buffer); // [3] Size = Size + rhs.Size; delete [] new_buffer; return *this; } 的不变量,总是有一个空终止符。 count参数中的MyString将复制所有元素和空终止符。

[3]:此时所有操作都已执行,我们可以交换旧缓冲区和新缓冲区,更新大小并释放Size+1(实际上是指旧缓冲区)

答案 1 :(得分:2)

首先,通常从operator+返回一个新对象,因为期望在对象上调用+不会改变对象本身。

MyString MyString::operator+ (const MyString& rhs)  
{  
  // ...

  return MyString(...);  

} 

请注意返回类型中缺少的引用(&):您将按副本返回新对象,而不是按引用返回。

其次,如果您delete开头为String,则无法复制其内容。请考虑operator+

char* tmp = new char[Size + rhs.Size + 1]; // +1 for the terminating '\0'      
for(int i = 0; i < Size ; i++)      
{
  // copy the contents of current object buffer, char-by-char
  tmp[i] = String[i]; 
}
for(int i = 0; i < rhs.Size+1; i++) // +1 to copy the terminating '\0' as well
{      
  // copy the contents of other object buffer, char-by-char
  tmp[i+Size] = rhs.String[i]; 
}
MyString result;
delete[] result.String;
result.String = tmp;
result.Size = Size+rhs.Size;      

return result;

operator+=有点棘手,因为你需要操纵当前对象的缓冲区:

char* tmp = new char[Size + rhs.Size + 1]; // +1 for the terminating '\0'      
for(int i = 0; i < Size ; i++)      
{      
  tmp[i] = String[i]; 
}
for(int i = 0; i < rhs.Size+1; i++) // +1 to copy the terminating '\0' as well
{      
  tmp[i+Size] = rhs.String[i]; 
}
delete[] String;
String = tmp;
Size += rhs.Size;      

return *this;

更新:我假设您也在类析构函数中调用delete[] - 您应该这样做。也不难想象,你会想要从一个MyString对象到另一个{{1}}对象进行分配。这将导致cosider rule of three:如果你需要构造函数,复制构造函数或赋值运算符中的任何一个,你很可能需要全部三个。