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

慣用的な方法は、 に機能を実装し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常に null ターミネータがあると仮定します。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想像するのも難しくありません。あるオブジェクトから別のオブジェクトへの割り当てを実行したいと思うでしょう。これにより、3 つのルールが考慮されます。desgtructor、copy-constructor、または代入演算子のいずれかが必要な場合は、3 つすべてが必要になる可能性が高くなります。

于 2012-04-30T00:11:58.343 に答える