演算子のリロード+構造解析関数



最近、演算子のリロードと構造解析関数を学習するとき、+をリロードするとき、等号の左側の値によく問題が発生し、1日以上の研究を経て、やっとこの問題を解決しました.今、この問題の解決方法を記録して、お互いに勉強します.初めての投稿ですが、足りない点も含めて!
質問:+を再ロードした後、等号左の値にエラーが発生しました.
ソリューション:リロード=以下はいくつかの詳細な説明です./*-------------------------------------------- CString 1. +, “123”+“456”(=“123456”); 2. +=, “123”+=“456”(=“123456”); 3. =; 4. ; --------------------------------------------*/ #include #include class CString { char *m_str; int m_Length; public: /* : */ CString(); /* : ch: */ CString(const char * ch); /* : str: CString , , */ CString(const CString& str); /* : +, str: CString : */ CString operator+(const CString& str) const; /* : +=, str: ( ) CString */ void operator+=(const CString& str); /* : =, str: */ void CString::operator=(const CString & str); /* : : */ char *GetStr(); /* : , */ ~CString(); }; ​ int main() { CString str1("123"); CString str2("456"); CString str3; CString str4(str1 + str2); (1) CString str5 = str1 + str2;     (2) str3 = str1 + str2; (3) printf("%s+%s=%s
", str1.GetStr(), str2.GetStr(), str4.GetStr()); printf("%s+%s=%s
", str1.GetStr(), str2.GetStr(), str3.GetStr()); printf("str1=%s,str2=%s,", str1.GetStr(), str2.GetStr()); str1 += str2; printf("str1+=str2,str1=%s
", str1.GetStr()); return 0; } CString::CString() { } ​ CString::CString(const char * ch) { m_Length = strlen(ch); m_str = new char[m_Length + 1]; strcpy_s(m_str, m_Length + 1, ch); } ​ CString::CString(const CString & str)   { //*this = str;( =, 。 ) m_Length = str.m_Length; m_str = new char[m_Length + 1]; strcpy_s(m_str, m_Length + 1, str.m_str); } ​ CString CString::operator+(const CString & str) const { CString str_new; str_new.m_Length = m_Length + str.m_Length; str_new.m_str = new char[str_new.m_Length + 1]; strcpy_s(str_new.m_str, m_Length + 1 , m_str); strcat_s(str_new.m_str, str_new.m_Length + 1, str.m_str);       // return str_new; //return str_new Temp, , , str_new } ​ void CString::operator+=(const CString & str) { char *ch = new char[m_Length + 1]; strcpy_s(ch, m_Length + 1, m_str); int length = strlen(str.m_str); m_Length += length; delete m_str; m_str = NULL; m_str = new char[m_Length + 1]; strcpy_s(m_str, strlen(ch) + 1, ch); strcat_s(m_str, m_Length + 1 , str.m_str); delete[] ch; ch = NULL; } ​ ​ void CString::operator=(const CString & str) { m_Length = strlen(str.m_str); m_str = new char[m_Length + 1]; strcpy_s(m_str, m_Length + 1, str.m_str); ​ } ​ char * CString::GetStr() { return m_str; } ​ CString::~CString() { delete[] m_str;     m_str = NULL; }
文字列クラスCStringを書く
1.重荷+、「123」+「456」を実現する(=「123456」);
2.重荷重+=、「123」+=「456」(=「123456」)を実現する.
3.重荷重=;
4.コピー構築関数を書き換える.
--------------------------------------------*/
#include
#include
class CString
{
char *m_str;
int m_Length;
public:
/*関数の役割:パラメトリック関数なし*/
CString();
/*関数の役割:文字ポインタによるパラメトリック構造
パラメータch:文字列を指すポインタ*/
CString(const char * ch);
/*関数の役割:コピー構造
パラメータstr:テンプレートとして同じオブジェクトを作成するCStringタイプのオブジェクト*/
CString(const CString& str);
/*関数の役割:演算子+を再ロードすることで、2つの文字列を加算する操作を実現します.
パラメータstr:加算された2番目のCStringオブジェクト
戻り値:2つのオブジェクトが加算された結果*/
CString operator+(const CString& str) const;
/*関数の役割:演算子+=を再ロードすることで、ある文字列を別の文字列の末尾に追加する操作を実現します.
パラメータstr:現在の文字列(この関数を呼び出す文字列)の後ろにあるCStringオブジェクト*/
void operator+=(const CString& str);
/*関数の役割:演算子=を再ロードすることによって、割り当て操作を実現する
パラメータstr:ソースオブジェクト*/
void CString::operator=(const CString & str);
/*関数の役割:オブジェクトの文字列を返します.
戻り値:オブジェクト内の文字列へのポインタ*/
char *GetStr();
/*関数の役割:構造関数はオブジェクトを保存するメモリ領域を空にし、*/を解放します.
~CString();
};

int main()
{
CString str1("123");
CString str2("456");
CString str3;
CString str4(str1 + str2); (1)
CString str5 = str1 + str2;     (2)
str3 = str1 + str2; (3)
printf("%s+%s=%s", str1.GetStr(), str2.GetStr(), str4.GetStr());
printf("%s+%s=%s", str1.GetStr(), str2.GetStr(), str3.GetStr());
printf("str1=%s,str2=%s,", str1.GetStr(), str2.GetStr());
str1 += str2;
printf("str1+=str2,str1=%s", str1.GetStr());
return 0;
}
CString::CString()
{
}

CString::CString(const char * ch)
{
m_Length = strlen(ch);
m_str = new char[m_Length + 1];
strcpy_s(m_str, m_Length + 1, ch);
}

CString::CString(const CString & str)  
{
//*this = str;(この行文は、次の3行の文の代わりに、リロードされた演算子=を呼び出します.この行文と次の3行の文の2つを選択します).
m_Length = str.m_Length;
m_str = new char[m_Length + 1];
strcpy_s(m_str, m_Length + 1, str.m_str);
}

CString CString::operator+(const CString & str) const
{
CString str_new;
str_new.m_Length = m_Length + str.m_Length;
str_new.m_str = new char[str_new.m_Length + 1];
strcpy_s(str_new.m_str, m_Length + 1 , m_str);
strcat_s(str_new.m_str, str_new.m_Length + 1, str.m_str);//ここで注意したいのは、2番目のパラメータがターゲット文字列バッファのサイズであることです
return str_new; //returnは、コピーコンストラクション関数を呼び出してstr_を作成します.Newオブジェクトがそっくりな一時オブジェクトTempを返し、解析関数を呼び出してオブジェクトstr_new析出
}

void CString::operator+=(const CString & str)
{
char *ch = new char[m_Length + 1];
strcpy_s(ch, m_Length + 1, m_str);
int length = strlen(str.m_str);
m_Length += length;
delete m_str;
m_str = NULL;
m_str = new char[m_Length + 1];
strcpy_s(m_str, strlen(ch) + 1, ch);
strcat_s(m_str, m_Length + 1 , str.m_str);
delete[] ch;
ch = NULL;
}


void CString::operator=(const CString & str)
{
m_Length = strlen(str.m_str);
m_str = new char[m_Length + 1];
strcpy_s(m_str, m_Length + 1, str.m_str);

}

char * CString::GetStr()
{
return m_str;
}

CString::~CString()
{
delete[] m_str;    
m_str = NULL;
}
文(1)と文(2)の実行手順は同じです.文(1)を例に実行順序を説明します.CString str4(str1 + str2); (1) (1)
ステップ1:演算子+のリロード関数を呼び出し、計算します.ローカルオブジェクトstr_を計算new.
ステップ2:演算子+リロード関数が返されます.リロード関数が返されると、コピーコンストラクション関数を呼び出してオブジェクトstr_を作成します.newそっくりのテンポラリオブジェクトTempを返し,テンポラリオブジェクトTempの名前をstr 4に変更する.(ここでオブジェクトstr 4はまだ宣言されていませんが、いっそ戻ってきたオブジェクトの名前を直接変更し(わがままです!!)、一度にオブジェクトを定義したり、一度にオブジェクトを解放したりする手間を省きます.このように理解しやすいように、具体的な操作手順はアセンブリを検討してください)
ステップ3:構造関数を呼び出します.解析関数を呼び出し、ローカルオブジェクトstr_new析出.(第2ステップと第3ステップはreturn文の仕事です)
第3ステップの実行が完了すると、文(1)は実行済みになります.
次に、文(3)の実行順序を説明する. CString str3; CString str3; str3 = str1 + str2; (3) (3)
ステップ1:演算子+のリロード関数を呼び出し、計算します.ローカルオブジェクトstr_を計算new.
ステップ2:演算子+リロード関数が返されます.リロード関数が返されると、コピーコンストラクション関数を呼び出してオブジェクトstr_を作成します.newそっくりの一時オブジェクトTempは,オブジェクトTempを返す.
ステップ3:構造関数を呼び出します.解析関数を呼び出し、ローカルオブジェクトstr_new析出.(第2ステップと第3ステップはreturn文の仕事です)
ステップ4:演算子=リロード関数を呼び出します.演算子=リロード関数を呼び出し、返された一時オブジェクトTempの値を深くコピーし、宣言されたオブジェクトstr 3にコピーします.
ステップ5:構造関数を呼び出します.テンポラリオブジェクトTempの深いコピーが完了したら、構造関数を呼び出し、テンポラリオブジェクトTempを解析します.
説明:以前にオブジェクトstr 3に対する宣言があったため、文(3)を実行する際に、既存のオブジェクトstr 3に一時オブジェクトをコピーし、一時オブジェクトTempを呼び出して構造関数を解析します.
まとめ
演算子+リロード関数を呼び出した後、=左のオブジェクトが宣言されていない場合は、演算子+のリロード関数が返す一時変数の名前を=左のオブジェクトの名前に変更します.=左のオブジェクトの場合は、演算子+リロード関数で返される一時変数をパラメータとして宣言され、=左のオブジェクトは演算子=リロード関数を呼び出します.等演算子=の関数が返された後、解析関数を呼び出し、一時オブジェクトを解析します.
注:ここでは演算子=を再ロードする必要があります.演算子=を再ロードしない場合、文(3)の=ここでは浅いコピーが行われます.str 3が宣言されているため、プログラムは構造関数を呼び出して演算子+再ロード関数が返す一時変数を解析します.これにより、次の2つの問題が発生します.
第1に、オブジェクトstr 3のポインタと一時オブジェクトのポインタは、浅いコピーが行われたため、同じメモリ領域を指す.プログラム呼び出し解析関数が一時変数を解析した後、オブジェクトstr 3のポインタは野ポインタであり、オブジェクトstr 3は不完全である.
第二に、浅いコピーが行われたため、プログラムが終了する前に構造関数を呼び出し、オブジェクトstr 3のポインタに割り当てられたメモリを動的に削除するとエラーが発生する.実は、このブロックのメモリは以前に解放され、繰り返し解放されてエラーが発生しました.