6

私は、教育目的と必要性のために、独自の C++ String クラスを作成しようとしています。
まず、私は演算子についてあまり知らないので、演算子を学びたいと思っています。クラスの作成を開始しましたが、実行するとプログラムがブロックされますが、クラッシュはしません。
さらに読む前に、次のコードを見てください。

class CString
{
private:
  char* cstr;
public:
  CString();
  CString(char* str);
  CString(CString& str);
  ~CString();

  operator char*();
  operator const char*();
  CString operator+(const CString& q)const;
     CString operator=(const CString& q);
};

まず第一に、私はすべてが正しいと宣言したかどうか確信が持てません。私はそれについてググってみましたが、オーバーロードに関するすべてのチュートリアルは、非常に単純ですが、それぞれがいつどのように呼び出されるかを説明していない基本的なアイデアを説明しています。たとえば、my = 演算子では、プログラムは CString(CString& str); を呼び出します。しかし、私には理由がわかりません。
以下の cpp ファイルも添付しました。

CString::CString()
{
 cstr=0;
}
CString::CString(char *str)
{
 cstr=new char[strlen(str)];
 strcpy(cstr,str);
}
CString::CString(CString& q)
{
 if(this==&q)
  return;
 cstr = new char[strlen(q.cstr)+1];
 strcpy(cstr,q.cstr);
}
CString::~CString()
{
 if(cstr)
  delete[] cstr;
}
CString::operator char*()
{
 return cstr;
}
CString::operator const char* ()
{
 return cstr;
}
CString CString::operator +(const CString &q) const
{
 CString s;
 s.cstr = new char[strlen(cstr)+strlen(q.cstr)+1];
 strcpy(s.cstr,cstr);
 strcat(s.cstr,q.cstr);
 return s;
}
CString CString::operator =(const CString &q)
{
 if(this!=&q)
 {
  if(cstr)
   delete[] cstr;
  cstr = new char[strlen(q.cstr)+1];
  strcpy(cstr,q.cstr);
 }
 return *this;
}


テストのために、このCString a = CString("Hello") + CString(" World"); と同じくらい単純なコードを使用しました。
printf(a);
デバッグしようとしましたが、ある時点で迷子になります。最初に、「hello」と「world」のコンストラクターを 2 回呼び出します。次に、 + 演算子で取得しますが、これで問題ありません。次に、空の文字列のコンストラクターを呼び出します。その後、「CString(CString& str)」に入り、今は迷っています。なぜこうなった?この後、「Hello World」を含む文字列がデストラクタにあることに気付きました (数回続けて)。再び私は非常に困惑しています。char* から Cstring に再度変換した後、前後に停止します。= 演算子に入ることはありませんが、それ以上進むこともありません。printf(a) には到達しません。
これにはVisualStudio 2010を使用していますが、基本的には標準のC++コードにすぎないため、それほど大きな違いはないと思います

4

4 に答える 4

4

この線:

cstr=new char[strlen(str)];

次のようにする必要があります。

cstr=new char[strlen(str) + 1];

また、自己割り当てのテストは、コピー コンストラクターでは意味がありません。新しいオブジェクトを作成しています。既存のオブジェクトと同じアドレスを持つことはできません。また、コピー コンストラクターは const 参照をパラメーターとして受け取る必要があります。

コードで代入演算子が使用されることを期待していた場合、間違っていると予想されます。このコード:

CString a = CString("Hello") + CString(" World");

基本的には次と同じです:

CString a( CString("Hello") + CString(" World") );

これはコピー構築であり、割り当てではありません。一時的な CString "Hello world" は、 が構築された後に (デストラクタを呼び出して) 破棄されます。

基本的に、コードはほぼ期待どおりに動作しているように聞こえます。

于 2010-05-16T10:57:45.787 に答える
3

strlenは使用せず、独自の文字列長を保存してください。文字列は、ヌルターミネータを持つことに依存してはなりません。ランダムなconstchar*が渡された場合は、このようなものを使用してもかまいませんが、内部操作の場合は、サイズを使用する必要があります。

また、演算子constchar*をconstオーバーロードにするのを忘れました。

于 2010-05-16T11:35:24.150 に答える
1

何が起こっているかは次のとおりです。

  1. コンストラクターは実際に 2 回呼び出されます。1 回は "hello" 用、もう 1 回は "world" 用です。順番は未定です。
  2. CString::operator + は 1 番目の CString ("hello") で呼び出され、2 番目の CString (" world") を引数として渡します。CString::operator + の戻り値は新しい CString です
  3. 初期化で割り当てているため、つまり: CString a = [CString result of operator +]、c ++はコピーコンストラクターを呼び出すだけです。したがって、CString(CString& )デバッガーに表示されている呼び出しです。

これで合計 4 つのオブジェクトが作成され、各文字列リテラル ("hello" と "world") に 1 つ、それらの連結 (CString::operator +呼び出しの結果) に 1 つ、結果 ( CString a = ...) を保持するために 1 つです。これらの一時オブジェクトには、デストラクタが呼び出されます。

printf が取得できない理由については、わかりません。このファイルにコードをコピーして貼り付けただけです。

#include <cstdio>
#include <cstring>

[your code]

int main(int argc,char* argv[]) {
  CString a = CString("hello") + CString(" world");
  printf(a);
}

結果の実行可能ファイルを実行するとhello world、出力が得られました。これは g++ 4.4 の Ubuntu 上にあります。VSデバッガーで何も出力されない理由が正確にはわかりません。

于 2010-05-16T11:10:33.890 に答える
0

あなたが犯したいくつかの間違い:

1. コピー コンストラクターの署名が間違っています。それは違いない:

CString(const CString& q)

2. op= 署名が間違っています。それは違いない:

CString& operator=(const CString& q)

ところで、それがコピーコンストラクターが呼び出された理由でもありました。最後にオブジェクトをコピーしましreturn *thisた(op =署名付き)。

3. CString インスタンスを許可しますcstr == NULL(デフォルトのコンストラクターはそのようなインスタンスになります)。ただし、ほとんどすべての関数 (コピー コンストラクター、operator +operator =) では、そのケースをうまく処理できません ( q.cstr == NULL)。

おそらく、最も簡単で安全な方法は、そのケースを許可せず、デフォルトのコンストラクターを次のように変更することです。

CString::CString()
{
   cstr = new char[1];
   cstr[0] = 0;
}
于 2010-05-16T12:07:59.333 に答える