0

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

我的 .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;
}

从 main.cpp 调用:

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

 String2 += String3;
 String2.Print ();

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

4

2 回答 2

3

惯用的方法是实现 in 中的功能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将复制所有元素和空终止符。

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

于 2012-04-30T00:50:57.397 回答
2

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

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

  return MyString(...);  

} 

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

其次,如果你deleteString开头,你将无法复制它的内容。考虑这个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对象到另一个对象进行关联。这将导致考虑三个规则:如果您需要解构函数、复制构造函数或赋值运算符中的任何一个,您很可能需要全部三个。

于 2012-04-30T00:11:58.343 回答