2010-05-16 135 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