自定义字符串类(C ++)

时间:2010-05-16 10:54:50

标签: c++ string reference overloading operator-keyword

我正在尝试编写自己的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);
};

首先,我不太确定我宣布一切正确。我尝试谷歌搜索它,但所有关于重载的教程解释了基本的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 a = CString(“Hello”)+ CString(“World”);
的printf(一);
我试过调试它,但在某一点上我迷路了。首先,它为“hello”和“world”调用构造函数2次。然后它在+运算符中就可以了。然后它调用空字符串的构造函数。之后它进入“CString(CString& str)”,现在我迷路了。为什么会这样?在此之后我注意到我的包含“Hello World”的字符串在析构函数中(连续几次)。我又一次非常困惑。再次从char *转换为Cstring后来回停止。它永远不会进入=运算符,但它也不会进一步发展。从未到达printf(a) 我使用VisualStudio 2010,但它基本上只是标准的c ++代码,因此我认为它不应该产生那么大的差异

4 个答案:

答案 0 :(得分: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 :(得分:3)

不要使用strlen,存储自己的字符串长度。不应该依赖该字符串来使用null终止符。如果你传入一个随机的const char *,可以使用它,但对于内部操作,你应该使用这个大小。

另外,你忘了让你的操作符const char *一个const重载。

答案 2 :(得分:1)

这是发生了什么:

  1. 构造函数确实被调用了两次。一次为“你好”,一次为“世界”。订单未定义。
  2. 在第一个CString(“hello”)上调用CString :: operator +,传递第二个CString(“world”)作为它的参数。 CString :: operator +的返回值是一个新的CString
  3. 由于你在初始化中分配,即:CString a = [CString result of operator +],c ++只会称你为复制构造函数。因此,您在调试器中看到的CString(CString& )调用。
  4. 现在,刚刚创建了4个对象,每个字符串文字对应一个(“hello”和“world”),一个用于串联(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调试器下它没有打印任何东西。

答案 3 :(得分: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;
}