2012-04-30 8 views
0

以下に示す演算子オーバーロード関数の両方で助けが必要です。私は実際に関数定義で代入を使わずにこれをどのように実装できるのか分かりません。オペレータのための+私の.cppファイル内複合代入と加算演算子のオーバーロード

コード:

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

String2 += String3; 
String2.Print(); 
:main.cppにから

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

コール:

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ファイルでオペレータのための

私の.cppファイルコードが間違っていることを知っていますが、いくつかの洞察は素晴らしいでしょう!

+2

(実際に古いバッファを指していること)、古いものと新しいバッファを交換するサイズを更新し、new_bufferを解放することができますが、削除された場合文字列に追加しようとする前に、あなたは非常に遠くに行くことはありません... –

+0

実際に+と+ =が必要な場合は、文字列を追加しますか? –

+0

2つの文字列(String1 = String2 + String3 + String4が動作する)を連結するには+演算子が必要ですが、String1 + String2を意味するString1 = String1 + String2を操作するには+ =が必要です。明確な例については – user1363061

答えて

2

まず、通常、オブジェクトの+を呼び出すとオブジェクト自体は変更されないため、operator+から新しいオブジェクトを返します。

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

    return MyString(...); 

} 

注戻り値の型から欠落している参照(&):あなたがいないことで、参照することにより、コピーの新しいオブジェクトを返しています。

第2に、最初にStringdeleteになった場合、その内容をコピーすることはできません。 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[]を呼び出すと仮定 - それはすべきです。想像するのも難しくありません。あなたはある物体から別のものへの訴えをしたいでしょう。これにより、コサイダーrule of threeにつながります。デストラクター、コピーコンストラクター、または代入演算子のいずれかが必要な場合は、3つすべてが必要になる可能性が最も高いです。

+0

+1。しかし、各関数の2番目の 'for'ループのインデックスを交換する必要があります。どちらの場合でも' String [i + Size] 'と' rhs.String [i] 'が必要です。 –

+0

@AdamLiss - ありがとう、固定 – Attila

+0

私はこれを試したとき私は次のエラーがあります:MyString.cpp:59:警告:ローカル変数âresultâへの参照が返され、出力はO! ???? – user1363061

3

operator+=に機能を実装し、それを使用してoperator+を実装することです。

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

注:正しく実装されているあなたのoperator+=よりもまず第仮定し、その後、operator+はフリー機能として自明実装可能であることは、我々その元のコピーなるように、最初の引数は、値によって渡されますoperator+=に変更できます。役に立つと思われるヒントがいくつかありますhere

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]:すべての操作が実行されているこの時点で、我々は

+0

*これを返す必要はありますか? – atlex2

+0

@ atlex2:はい、ありがとう –

関連する問題