2010-05-16 38 views
5

我試圖編寫自己的C++字符串類爲教育和需要的目的。
首先,我不太瞭解操作員,這就是爲什麼我想學習它們的原因。 我開始寫我的課,但是當我運行它時,它會阻止程序,但不會造成任何崩潰。
看看下面的代碼,請繼續閱讀之前:自定義字符串類(C++)

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); 
}; 

首先,我不敢肯定我聲明的一切權利。我試着googleing它,但所有關於重載的教程解釋了非常簡單的基本ideea,但沒有解釋如何以及何時調用每個東西。例如在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的一個= CString的( 「你好」)+ CString的( 「世界」);
printf(a);
我試着調試它,但是在一個點我迷路了。首先爲「hello」和「world」調用構造函數2次。然後,它在+運營商這是很好的。然後它調用空字符串的構造函數。之後,它進入「CString(CString & str)」,現在我迷路了。這是爲什麼發生?在此之後,我注意到包含「Hello World」的字符串在析構函數中(連續幾次)。我再次感到非常困惑。在從char *再次轉換爲Cstring並來回之後,它停止。它永遠不會進入=運算符,但它也不會進一步發展。 printf(a)永遠不會到達。
我使用VisualStudio的2010年這一點,但它基本上只是標準的C++代碼,因此我不認爲它應該使多大的差別在於

+0

我理解的教育,但對於「需要」的目的?你不喜歡標準的std :: string? – Nikko 2010-05-16 11:57:41

+0

坦率地說,沒有。我夢想這個智能且易於使用的代碼。我發現std :: string不能做這樣的事情:string a = string(「Hello」)+ string(「world」)or string a = String(「Hello」)+「World」因爲它缺少+過載。 更多的是,我必須在我的項目的這一部分中使用字符串進行很多工作,因此要求具有我想要的所有功能以及我想要的功能。 我希望我不會因爲這樣說而受到傷害。 – Sanctus2099 2010-05-16 12:05:14

+0

你真的不能做的是:str3 =「qwe」+「rty」; 在標準中,operator +是字符串的全局函數。 對我來說,重新定義一個std :: string是一個初學者的錯誤,只是因爲你需要它而不是有特定的需求。 – Nikko 2010-05-16 12:41:36

回答

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」將被銷燬(調用析構函數)。

基本上,它聽起來好像你的代碼或多或少按預期工作。

+1

+1 GotW#11 http://www.gotw.ca/gotw/011中提供了自我分配檢查功能。 htm如果我沒有記錯的話,本書的最新版本顯示瞭如何讓測試評估爲真實(儘管我不記得具體是怎麼回事,但我猜測某種排列方式是新的):) – 2010-05-16 11:27:47

+0

是的 - 它的目的是建議這樣做是可笑的。沒有理由在拷貝構造函數中執行這樣的檢查,這是不可能的。 – Puppy 2010-05-16 11:31:52

+0

是的,你是對的。對於自賦值的測試在構造函數中沒有意義,因爲它在創建之前不能存在。並感謝您指出+1事物。 – Sanctus2099 2010-05-16 11:54:05

1

這裏是發生了什麼事情:

  1. 構造的確叫了兩聲。曾經是「你好」,曾經是「世界」。訂單未定義。
  2. 在第一個CString(「hello」)上調用CString :: operator +,傳遞第二個CString(「world」)作爲它的參數。 CString :: operator +的返回值是一個新的CString
  3. 由於您在初始化中進行賦值,例如:CString a = [CString result of operator +],C++將會調用您的拷貝構造函數。因此調用您在調試器中看到的CString(CString&)。現在

,這只是創建總共4個對象,每個字符串文字(「你好」和「世界」),一個是爲串接(在CString::operator +調用的結果,和一個舉行。結果(CString a = ...)的臨時對象的每一個都會有它叫做析構函數

至於爲什麼你沒有得到的printf的,我不知道我只是複製粘貼代碼在這個文件中:

#include <cstdio> 
#include <cstring> 

[your code] 

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

而當我運行得到的可執行文件時,我得到了hello world作爲輸出。這是在Ubuntu的g ++ 4.4。不完全確定爲什麼在VS調試器下它不打印任何東西。

+0

我對同樣的事情做出了努力,但顯然我必須讓操作符const char * const過載 – Sanctus2099 2010-05-16 11:52:57

3

不要使用strlen,存儲自己的字符串長度。該字符串不應該依賴於具有空終止符。如果你傳入的是一個隨機的const char *,那麼可以使用它,但是對於內部操作,你應該使用這個大小。

此外,你忘了讓你的操作符const char * const過載。

+0

非常感謝。最後一點,你告訴我關於修復它。 – Sanctus2099 2010-05-16 11:52:12

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; 
} 
+0

謝謝你的建議。我改變了簽名。事情是,在不同的地方我看到不同的標誌,所以我不確定哪一個是好的或「標準」的。 我看到了使默認構造函數爲null僅作爲終止字符串的要點。 – Sanctus2099 2010-05-16 12:20:44