Пользовательский класс строки (C ++) - PullRequest
6 голосов
/ 16 мая 2010

Я пытаюсь написать свой собственный класс 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");
Е (а);
Я попытался отладить его, но в какой-то момент я заблудился. Сначала он вызывает конструктор 2 раза «привет» и «мир». Тогда он попадает в оператор +, что нормально. Затем он вызывает конструктор для пустой строки. После этого он попадает в "CString (CString & str)", и теперь я заблудился. Почему это происходит? После этого я заметил, что моя строка, содержащая «Hello World», находится в деструкторе (несколько раз подряд). Я снова очень озадачен. После повторного преобразования из char * в Cstring и обратно он останавливается. Он никогда не попадает в оператор =, но и не идет дальше. printf (a) никогда не достигается.
Я использую VisualStudio 2010 для этого, но это в основном просто стандартный код на C ++, и поэтому я не думаю, что это должно что-то значить

Ответы [ 4 ]

4 голосов
/ 16 мая 2010

Линия:

cstr=new char[strlen(str)];

должно быть:

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

Кроме того, проверка на самостоятельное назначение не имеет смысла в конструкторе копирования - вы создаете новый объект - он не может иметь тот же адрес, что и любой существующий объект. И конструктор копирования должен принимать константную ссылку в качестве параметра,

Если бы в своем коде вы ожидали, что будет использоваться оператор присваивания, вы бы ожидали, что это неправильно. Этот код:

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

по сути то же самое, что и

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

которая является копией, а не назначением. Временная строка CString "Hello world" будет уничтожена (с вызовом деструктора) после того, как a будет построен.

По сути, это звучит так, как будто ваш код работает более или менее так, как ожидалось.

3 голосов
/ 16 мая 2010

Не используйте strlen, сохраняйте собственную длину строки. Строка не должна зависеть от наличия нулевого терминатора. Это нормально, если вы используете случайный константный символ *, но для внутренних операций следует использовать размер.

Кроме того, вы забыли сделать из оператора const char * const overload.

1 голос
/ 16 мая 2010

Вот что происходит:

  1. Конструктор действительно вызывается дважды. Один раз за "привет" и один раз за "мир". Заказ не определен.
  2. CString :: operator + вызывается на первой CString ("привет"), передавая в качестве аргумента вторую CString ("мир"). Возвращаемое значение 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 голосов
/ 16 мая 2010

Несколько ошибок, которые вы сделали:

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