演算子のリロード+構造解析関数
最近、演算子のリロードと構造解析関数を学習するとき、+をリロードするとき、等号の左側の値によく問題が発生し、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のポインタに割り当てられたメモリを動的に削除するとエラーが発生する.実は、このブロックのメモリは以前に解放され、繰り返し解放されてエラーが発生しました.