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

Compound assignment and add operator overloading

本文关键字:运算符 重载 添加 赋值 复合      更新时间:2023-10-16

我需要下面介绍的两个运算符重载函数的帮助。我不确定如何在不实际使用函数定义中的赋值的情况下实现这一点。

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

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;
}

主.cpp呼叫:

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

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

惯用的方法是在operator+=中实现功能,然后使用它来实现operator+。假设对于初学者来说,你的operator+=被正确实现,那么operator+作为一个自由函数是可以简单实现的:

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

注意:第一个参数是按值传递的,因此它是原始参数的副本,我们可以通过 operator+= .这里还有其他一些提示可能会对您有用。

现在回到实现operator+=,您应该了解的第一件事是您需要执行的操作是什么:您需要分配更长的缓冲区,从旧缓冲区复制,附加rhs字符串,交换旧缓冲区和新缓冲区(包含结果(并释放旧缓冲区。操作的顺序很重要,如果您在复制之前释放旧内容(就像您正在做的那样(,那么您就不能再从中复制。

// 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;
}

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

[2]:假设作为类型MyString的不变量,始终存在一个空终止符。count 参数中的Size+1将复制所有元素和 null 终止符。

[3]:此时所有操作都已经执行完毕,我们可以交换新旧缓冲区,更新大小和释放new_buffer(实际上指的是旧的缓冲区(

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

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

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

其次,如果您在开始时delete String,您将无法复制其内容。 考虑一下operator+

char* tmp = new char[Size + rhs.Size + 1]; // +1 for the terminating ''      
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 '' 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 ''      
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 '' as well
{      
  tmp[i+Size] = rhs.String[i]; 
}
delete[] String;
String = tmp;
Size += rhs.Size;      
return *this;

更新:我假设您还在类析构函数中调用delete[] - 您应该这样做。 也不难想象,你会想要从一个MyString对象到另一个对象执行断言。 这将导致三法则:如果你需要desgtructor,copy-constructor或赋值运算符中的任何一个,你很可能需要这三个