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

发布于 2024-09-01 12:52:52 字数 1770 浏览 2 评论 0原文

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

首先,我不太确定我声明的一切都是正确的。我尝试用谷歌搜索它,但所有关于重载的教程都解释了基本的想法,它非常简单,但缺乏解释如何以及何时调用每个东西。例如,在我的 = 运算符中,程序调用 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”调用构造函数两次。然后它就在 + 运算符中,这很好。然后它调用空字符串的构造函数。之后它进入“CString(CString& str)”,现在我迷路了。为什么会发生这种情况?之后,我注意到包含“Hello World”的字符串位于析构函数中(连续几次)。我再次感到非常困惑。再次从 char* 转换为 Cstring 并来回转换后,它会停止。它永远不会进入 = 运算符,但也不会更进一步。 printf(a) 永远不会到达。
我为此使用 VisualStudio 2010,但它基本上只是标准 C++ 代码,因此我认为它不会产生那么大的差异

I'm trying to write my own C++ String class for educational and need purposes.
The first thing is that I don't know that much about operators and that's why I want to learn them.
I started writing my class but when I run it it blocks the program but does not do any crash.
Take a look at the following code please before reading further:

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

First of all I'm not so sure I declared everything right. I tried googleing about it but all the tutorials about overloading explain the basic ideea which is very simple but lack to explain how and when each thing is called. For instance in my = operator the program calls CString(CString& str); but I have no ideea why.
I have also attached the cpp file below:

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

For testing I used a code just as simple as this
CString a = CString("Hello") + CString(" World");
printf(a);
I tried debugging it but at a point I get lost. First it calls the constructor 2 times for "hello" and for " world". Then it get's in the + operator which is fine. Then it calls the constructor for the empty string. After that it get's into "CString(CString& str)" and now I'm lost. Why is this happening? After this I noticed my string containing "Hello World" is in the destructor (a few times in a row). Again I'm very puzzeled. After converting again from char* to Cstring and back and forth it stops. It never get's into the = operator but neither does it go further. printf(a) is never reached.
I use VisualStudio 2010 for this but it's basically just standard c++ code and thus I don't think it should make that much of a difference

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深海夜未眠 2024-09-08 12:52:52

该行:

cstr=new char[strlen(str)];

应该是:

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

另外,自分配测试在复制构造函数中没有意义 - 您正在创建一个新对象 - 它不可能与任何现有对象具有相同的地址。并且复制构造函数应该采用 const 引用作为参数,

如果在您的代码中,您期望使用赋值运算符,那么您的期望是错误的。此代码:

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

本质上与: 相同,

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

这是复制构造,而不是赋值。 a 构造完成后,临时 CString“Hello world”将被销毁(调用析构函数)。

基本上,听起来您的代码或多或少按预期工作。

The line:

cstr=new char[strlen(str)];

should be:

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

Also, the test for self-assignment does not make sense in the copy constructor - you are creating a new object - it cannot possibly have the same address as any existing object. And the copy constructor should take a const reference as a parameter,

If in your code, you were expecting the assignment operator to be used, you would be expectining wrong. This code:

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

is essentially the same as:

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

which is copy construction, not assignment. The temporary CString "Hello world" will be destroyed (invoking the destructor) after a has been constructed.

Basically, it sounds as if your code is working more or less as expected.

紫罗兰の梦幻 2024-09-08 12:52:52

不要使用 strlen,存储您自己的字符串长度。不应依赖该字符串具有空终止符。如果您传入随机 const char* ,则可以使用此类,但对于内部操作,您应该使用大小。

另外,您忘记将运算符 const char* 设为 const 重载。

Don't use strlen, store your own string length. The string should not be depended on to have a null terminator. It's ok to use such if you're passed in a random const char*, but for internal operations, you should use the size.

Also, you forgot to make your operator const char* a const overload.

蝶…霜飞 2024-09-08 12:52:52

事情是这样的:

  1. 构造函数确实被调用了两次。一次是“你好”,一次是“世界”。顺序未定义。
  2. CString::operator + 在第一个 CString(“hello”)上调用,将第二个 CString(“world”)作为参数传递。 CString::operator + 的返回值是一个新的 CString
  3. 由于您在初始化中进行分配,即: CString a = [CString result of operator +],c++ 只会调用您的复制构造函数。因此,您在调试器中看到了对 CString(CString& ) 的调用。

现在,总共有 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 作为输出。不打印任何东西。

Here's what's going on:

  1. The constructor is indeed called twice. Once for "hello" and once for " world". The order is undefined.
  2. The CString::operator + is called on the 1st CString ("hello"), passing the second CString (" world") as it's argument. The return value of CString::operator + is a new CString
  3. Since you're assigning in initialization, i.e: CString a = [CString result of operator +], c++ will just call you're copy constructor. Hence the call to CString(CString& ) that you're seeing in the debugger.

Now, that's 4 total objects just created, one for each string literal ("hello", and " world"), one for the concatenation of those (the result of the CString::operator + call, and one to hold the result (CString a = ...). Each one of those temporary objects will have it's destructor called.

As for why you're not getting the printf, I have no idea. I just copy pasted your code in this file:

#include <cstdio>
#include <cstring>

[your code]

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

And when I ran the resulting executable, I got hello world as the output. This is on Ubuntu with g++ 4.4. Not exactly sure why under the VS debugger it's not printing anything.

開玄 2024-09-08 12:52:52

你犯的几个错误:

1. 复制构造函数签名错误。一定是:

CString(const CString& q)

2.op=签名错误。一定是:

CString& operator=(const CString& q)

顺便说一句,这也是调用复制构造函数的原因。最后,您执行了 return *this 操作,复制了对象(带有您的 op= 签名)。

3. 您允许使用 cstr == NULL 的 CString 实例(您的默认构造函数将产生这样的实例)。不过,在几乎所有函数(复制构造函数、operator +operator =)中,您都不能很好地处理这种情况(q.cstr == NULL代码>)。

也许最简单和最安全的方法是禁止这种情况并将默认构造函数更改为:

CString::CString()
{
   cstr = new char[1];
   cstr[0] = 0;
}

A few mistakes you made:

1. Copy constructor signature is wrong. It must be:

CString(const CString& q)

2. op= signature is wrong. It must be:

CString& operator=(const CString& q)

Btw., that was also the reason that the copy constructor was called. You did a return *thisin the end which copied the object (with your op= signature).

3. You allow CString instances with cstr == NULL (your default constructor will result in such an instance). Though, in almost all functions (copy constructor, operator +, operator =) you don't handle that case well (q.cstr == NULL).

Maybe the easiest and safest way would be to just disallow that case and change your default constructor to:

CString::CString()
{
   cstr = new char[1];
   cstr[0] = 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文