Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Создание Класса Строка (С++)

33K
11 декабря 2007 года
1ntro
7 / / 11.12.2007
Очень нужна помощь вот с такой задачей:

 
Код:
Разработать класс для представления объекта строка.
Определить конструктор с одним параметром целого типа – длина строки,
который можно использовать как конструктор умолчания.
Определить конструктор, который копирует в новую строку n первых символов другой
строки и который можно использовать как конструктор копирования.
Определить деструктор.
Определить преобразования из вещественного числа в строку, представляющую это
число, и из строки в вещественное число.


Собственно вот.. Заранее спасибо
320
11 декабря 2007 года
m_Valery
1.0K / / 08.01.2007
Вот класс строка , не совсем твой,но переделать будет не трудно.
33K
11 декабря 2007 года
1ntro
7 / / 11.12.2007
Спасибо - попробую
350
12 декабря 2007 года
cheburator
589 / / 01.06.2006
Дополнения к ссылке, приведенной m_Valery.
 
Код:
class String                    //  Объявление строкового класса
{
       // Конструктор по умолчанию убираем - у нас будет свой
       String(size_t length = 0); //  Конструктор, который можно использовать как конструктор по умолчанию
       // Конструктор копирования также убираем - у нас свой
       String(const String& s, size_t symbols = -1);  //  Конструктор, который можно использовать как конструктор копирования
       operator float () const; // Оператор преобразования строка => число
       String (double d); // Конструирование из числа
}

Соответственно, дорабатываем реализации методов.
350
12 декабря 2007 года
cheburator
589 / / 01.06.2006
Собственно, вот (см. вложение).
33K
12 декабря 2007 года
1ntro
7 / / 11.12.2007
Спасибо, щас накалякаем
33K
16 декабря 2007 года
1ntro
7 / / 11.12.2007
Цитата:
#include <vcl.h>
#include <iostream.h>
#include <math.h>
#pragma hdrstop
#pragma argsused
#pragma warning (disable : 4996)
class blabla
{
private:
size_t maxlen;
size_t len;
char* S;
public:
blabla(size_t len = 0);
friend ostream& operator<<(ostream&, const blabla&);
friend istream& operator>>(istream&, blabla&);
blabla(const char* s);
blabla(const blabla &s, size_t symbols = -1);
~blabla() { delete [] S; }
size_t GetLen() const { return len; }
size_t GetMaxLen() const { return maxlen; }
operator double ();
blabla (double d);

};
istream& operator>>(istream& is, blabla& str)
{
const int N = 65536;
char temp[N] = {0};
size_t Length = 0,
Total = 0;
do
{
is.getline(temp + Total, N - Total);
Length = strlen(temp + Total);
if(Length == 0)
break;
Total += Length + 1;
temp[Total - 1] = '\n';
} while(Total < N);
temp[Total - 1] = 0;
str = temp;
return is;
}
ostream& operator<<(ostream& os, const blabla& str)
{
os << str.S;
return os;
}
blabla::blabla(size_t l)
:maxlen (l), len (0), S(new char [maxlen+1])
{
S[0] = 0;
}
blabla::blabla(const char* s)
:maxlen (strlen(s)), len(maxlen), S (new char[len+1])
{
strcpy (S, s);
}
blabla::blabla(const blabla &s, size_t symbols)
{
size_t slen = s.GetLen();
len = maxlen = ((symbols == -1) ? slen : ((symbols > slen) ?slen : symbols));
S = new char [len+1];
strncpy (S, s.S, len);
S[len] = 0;
}
blabla::operator double ()
{
return atof (S);
}
blabla::blabla (double d)
{
len = strlen(S);
}
int main(int argc, char* argv[])
{
blabla a;
cout << "Input string:\n";
cin >> a;
cout<<double(a);
return 0;
}


Кто может посмотреть код на наличие ошибки? что-то не так он работает х_Х

350
16 декабря 2007 года
cheburator
589 / / 01.06.2006
Конкретнее, в чем ошибка? Выкладывай все сюда
33K
16 декабря 2007 года
1ntro
7 / / 11.12.2007
При трансформации стринг-дабл результат выдает число 0...
33K
16 декабря 2007 года
1ntro
7 / / 11.12.2007
Цитата:
len = maxlen = ((symbols == -1) ? slen : ((symbols > slen) ?slen : symbols));


здесь получаем
[BCC32 Warning] File5.cpp(63): W8012 Comparing signed and unsigned values

9.3K
22 марта 2008 года
iridum
175 / / 26.08.2007
size_t symbols - unsigned

-1 - signed

 
Код:
len = maxlen = ((symbols == -1) ? slen : ((symbols > slen) ?slen : symbols));


Гениальная строчка. К сожалению моего опыта далеко не хватает чтобы осознать зачем так надо было писать) уникальная конструкция.

size_t symbols = -1 определяется вначале, можно приравнять вначале 0 и сравнивать с 0-м

 
Код:
blabla(const blabla &s, size_t symbols = 0);
.....
len = maxlen = ((!symbols) ? slen : ((symbols > slen) ?slen : symbols));
48K
06 декабря 2009 года
Akord
20 / / 06.12.2009
Задание

Разработать реализацию класса String, позволяющего оперировать с
текстовыми строками, как с базовыми типами данных. Класс должен обеспечивать выполнение следующих операции:

- инициализация (оператор присваивания =) +
- конкатенация строк (оператор +) +
- сравнение строк (операторы <,>,<=,>=,==, !=)
- определение длины (метод length) +
- поиск подстроки текста (метод find)
- поиск и замена текста (метод replace)
- вывод в стандартный поток вывода (>>); +
- ввод из стандартного потока ввода (<<). +


Помогите плиз сделать остальное!
12K
06 декабря 2009 года
Ghox
297 / / 26.07.2009
Лучше бы было создать новую тему, а не поднимать старую...
Цитата: Akord
Задание

Разработать реализацию класса String, позволяющего оперировать с
текстовыми строками, как с базовыми типами данных. Класс должен обеспечивать выполнение следующих операции:

- инициализация (оператор присваивания =) +
- конкатенация строк (оператор +) +
- сравнение строк (операторы <,>,<=,>=,==, !=)
- определение длины (метод length) +
- поиск подстроки текста (метод find)
- поиск и замена текста (метод replace)
- вывод в стандартный поток вывода (>>); +
- ввод из стандартного потока ввода (<<). +


Помогите плиз сделать остальное!


То, что уже сделано - это то что помечено знаком +?
Чтобы вам помогли сделать все остальное, вам нужно показать что вы уже сделали.
Выложите имеющееся у вас определение класса, и функцию инициализации (чтобы было понятно как у вас реализовано хранение содержимого строки).

34K
06 декабря 2009 года
muturgan
96 / / 01.10.2009
Цитата: 1ntro
здесь получаем
[BCC32 Warning] File5.cpp(63): W8012 Comparing signed and unsigned values


У Вас тут происходит сравнение беззнакового целого symbols (типа size_t) и -1. Вот компилятор и предупреждает.
Update: Упс, отстал от обсуждения, сорри. :)

48K
06 декабря 2009 года
Akord
20 / / 06.12.2009
Цитата: Ghox

То, что уже сделано - это то что помечено знаком +?
Чтобы вам помогли сделать все остальное, вам нужно показать что вы уже сделали.
Выложите имеющееся у вас определение класса, и функцию инициализации (чтобы было понятно как у вас реализовано хранение содержимого строки).



Не стал создавать новую тему, чтобы не было тематической тавтологии, обычно это чревато)
Да, то, что плюс, есть.
Вот код, без lenght и конкатенации, чтобы компактно вышло:

Код:
class string {
      struct rep
  {
          char* s;          
          int   n;          
  };
      rep *p;

  public:
      string(char *);      
      string();          
      string(string &);    
      string& operator=(char *);
      string& operator=(string &);
      ~string();

      friend ostream& operator<<(ostream&, string&);
      friend istream& operator>>(istream&, string&);

      friend int operator==(string& x, char* s)
          {return strcmp(x.p->s, s) == 0; }

      friend int operator==(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) == 0; }
  };
  string::string()
  {
      p = new rep;
      p->s = 0;
      p->n = 1;
  }

  string::string(char* s)
  {
      p = new rep;
      p->s = new char[ strlen(s)+1 ];
      strcpy(p->s, s);
      p->n = 1;
  }

  string::string(string& x)
  {
      x.p->n++;
      p = x.p;
  }

  string::~string()
  {
      if (--p->n == 0) {
          delete p->s;
          delete p;
      }
  }

  string& string::operator=(char* s)
  {
      if (p->n > 1) {    // разъединить себя
          p->n--;
          p = new rep;
      }
      else if (p->n == 1)
          delete p->s;

      p->s = new char[ strlen(s)+1 ];
      strcpy(p->s, s);
      p->n = 1;
      return *this;
  }

  string& string::operator=(string& x)
  {
      x.p->n++;
      if (--p->n == 0) {
          delete p->s;
          delete p;
      }
      p = x.p;
      return *this;
  }

  ostream& operator<<(ostream& s, string& x)
  {
      return s << x.p->s << "\n";
  }

  istream& operator>>(istream& s, string& x)
  {
      char buf[256];
      s >> buf;
      x = buf;
      cout << x << "\n";
      return s;
  }
12K
06 декабря 2009 года
Ghox
297 / / 26.07.2009
Итак, для хранения содержимого строки используется char* s в составе структуры rep, указатель на которую является переменной класса.

Насчет того что нужно сделать:
Цитата:
- сравнение строк (операторы <,>,<=,>=,==, !=)


У вас уже есть операторы "==":

 
Код:
friend int operator==(string& x, char* s)
          {return strcmp(x.p->s, s) == 0; }

      friend int operator==(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) == 0; }

По аналогии с ними можно сделать остальные, вот только тип возвращаемого значения (и в новых операторах, и в имеющихся) надо бы сделать bool:
Код:
friend bool operator==(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) == 0; }
      friend bool operator<(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) < 0; }
      friend bool operator>(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) > 0; }
      friend bool operator<=(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) <= 0; }
      friend bool operator>=(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) >= 0; }
      friend bool operator<(string& x, string& y)
          {return strcmp(x.p->s, y.p->s) < 0; }
      // также можно сделать аналогичные операторы для сравнения string с char*

Поиск можно сделать так. Сделать функцию которая принимает на вход строку, которую нужно найти в текущей, и номер позиции начиная с которой надо искать. И еще нужно создать какое-либо значение, которое будет возвращаться в случае, если строка не найдена.
Код:
class string {
      // ...
public:
      // если компилятор не позволит здесь такое присваивание
      // то сделать его после объявления класса:
      static const int npos = -1;
      int find(const char*, int = 0);
      int find(const string&, int = 0);
      // ...
};
// ...
int string::find(const char *s, int n)
{
      const int len = strlen(p->s);
      const int lenx = strlen(s);
      if(lenx == 0 || lenx > len || n >= len || n + lenx > len)
            return npos;
      if(n < 0)
            n = 0;
      for(; n <= len - lenx; ++n)
      {
            int i = 0;
            while(i < lenx && p->s[n + i] == s)
                  ++i;
            if(i == lenx)
                  return n;
      }
      return npos;
}

int string::find(const string& x, int n)
{
      return find(x.p->s, n);
}

// пример вызова
int main()
{
      // ...
      n = str1.find(str2);
      if(n != string::npos)
            // ...
}

А вот насчет replace будет посложнее - надо подумать, может позже напишу (или кто-то другой)...

А пока еще замечания
1. Непонятно назначение другой переменной из структуры rep - переменная int n...
2. Конструктор копирования:
 
Код:
string::string(string& x)
  {
      x.p->n++;
      p = x.p;
  }

Происходит присваивание значения указателя p текущего объекта к значению p объекта-аргумента. В итоге у вас получается, что после вызова конструктора копирования имеются два разных объекта string с общим содержимым, и впоследствии если в одном из них строка будет изменена, то и в другом тоже изменится (указатели-то на одно и то же указывают). Думаю что это неправильно, и надо как-то так:
 
Код:
string::string(const string& x)
  {
      p = new rep;
      p->s = new char[strlen(x.p->s) + 1];
      strcpy(p->s, x.p->s);
      p->n = x.p->n;
      p->n++;
  }
48K
06 декабря 2009 года
Akord
20 / / 06.12.2009
Цитата: Ghox

По аналогии с ними можно сделать остальные



Спасибо, сделано, все работает, и метод find тоже.

 
Код:
int   n;

это счетчик ссылок.
Насчет коструктора копирования - да, недодумал. Все-таки не зря мне казалось, что там что-то не так)
Благодарен за подробные объяснения.
Если Вы(или кто-то другой) поможете мне с replace - будет совсем замечательно)

И еще, я видимо неправильно написал конкатенацию строк, не могли бы Вы проверить?
 
Код:
string& string::operator+(char* s)
  {
      string temp;
      temp.length = strlen(p->s) + strlen(s);
temp = new char[temp.length + 1];
    strcpy(temp, p->s);      
    strcat(temp, s);      
    return temp;
}
12K
08 декабря 2009 года
Ghox
297 / / 26.07.2009
По поводу оператора +: замечания в коде:
Код:
[COLOR="Red"]// указывать результат в виде ссылочной переменной здесь, ИМХО, неправильно[/COLOR]
  string& string::operator+(char* s)
  {
      string temp;
          [COLOR="Red"]// length, я так понимаю, фунция класса string, а не переменная?
          // почему тогда использование length как будто это переменная?[/COLOR]
      temp.length = strlen(p->s) + strlen(s);
temp = new char[temp.length + 1];
    [COLOR="Red"]// для функций strcpy и strcat оба аргумента должны иметь тип char*,
    // а не string как это сделано здесь[/COLOR]
    strcpy(temp, p->s);      
    strcat(temp, s);      
    return temp;
}

И я бы наверно так переписал оператор:
 
Код:
string string::operator+(const char* s)
{
    char * temp = new char[strlen(p->s) + strlen(s) + 1];
    strcpy(temp, p->s);
    strcat(temp, s);
    string result(temp);
    delete[] temp;
    return result;
}

А по поводу функции replace - попробовал сделать с использованием уже имеющейся find и по аналогии с этой темой:
http://forum.codenet.ru/showthread.php?t=57967
Предвидя замечания Kogrom'а, скажу что писал эту функцию до того как занялся той темой (здесь просто времени не нашел чтобы запостить), при желании и здесь можно упростить (сделать более эффективный алгоритм), и сделать более удобочитаемым, но пока нет на это времени, да и может автору будет пока и этого достаточно...
Код:
class string {
      // ...
public:
      // ...
      void replace(const char*, const char*, bool = false, int = 0);
      void replace(const string&, const string&, bool = false, int = 0);
      // ...
};

void string::replace(const char *s1, const char *s2, bool replaceAll, int n)
{
      const int len = strlen(p->s);
      const int len1 = strlen(s1);
      const int len2 = strlen(s2);
      if(len == 0 || len1 == 0 || len1 > len || n + len1 > len)
            return;
      int * numpos = new int[len / len1 + 1];
      int pos1 = 0;
      do
            if((n = find(s1, n)) != npos)
                  numpos[pos1++] = n++;
      while(n != npos && replaceAll);
      if(!pos1)
      {
            delete[] numpos;
            return;
      }
      char * newstr = new char[len + (len2 - len1) * pos1 + 1];
      int i;
      for(n = 0, i = 0, int pos2 = 0; i < len; ++n, ++i)
            if(pos2 == pos1 || i < numpos[pos2])
                  newstr = p->s[n]
            else
            {
                  for(int j = 0; j < len2; ++i, ++j)
                        newstr = s2[j];
                  ++pos2;
                  --i;
                  n += len1 - 1;
            }
      newstr = '\0';
      delete[] p->s;
      p->s = newstr;
      delete[] numpos;
}

void string replace(const string& x1, const string& x2, bool replaceAll, int n)
{
      replace(x1.p->s, x2.p->s, replaceAll, n);
}
48K
08 декабря 2009 года
Akord
20 / / 06.12.2009
Я не могу сообразить. Конкатенация же должна быть перегруженным оператором? Надо писать еще и string string::operator+(string& x)?

И не могли бы вы объяснить, какой параметр что значит для метода replace?

Насчет эффективности можете не беспокоиться, я очень вам благодарен, что вы мне помогаете. Даже не надеялся, что так можно.
12K
10 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Akord
Я не могу сообразить. Конкатенация же должна быть перегруженным оператором? Надо писать еще и string string::operator+(string& x)?


Ну это вам должно быть виднее. Задача-то ставилась не мне. И не мною. :)
Но вообще я думаю что логично было бы и оператор конкатенации перегрузить (раз уж вы перегружаете другие операторы) - чтобы можно было вызывать и в случае string + char (что вы уже пытались сделать и что я вам исправил), и в случае string + string. Какие-то трудности с этим - не знаете как сделать?

Цитата: Akord
И не могли бы вы объяснить, какой параметр что значит для метода replace?


Если вы о параметрах вызова (то что передается в функцию):

  • const char *s1 - строка char, которую будете заменять в исходной строке
  • const char *s2 - строка char, на которую будете заменять в исходной строке
  • bool replaceAll - нужно ли заменить все найденные вхождения строки s1 на строку s2, или только первое (если таковое есть)? true - все, false - только первое
  • int n - с какой позиции (с какого символа) искать и, соответственно, заменять
Последние 2 параметра сделаны необязательными, для них установлены значения по умолчанию (см. объявление функции): для replaceAll - false, для int - 0 (искать с самого начала). Таким образом, если вам нужно заменить только первое вхождение строки, а поиск делать сначала, то эти три варианта вызова функции равнозначны:
 
Код:
string testString;
    // ...
    // все три варианта равнозначны
    testString.replace("str1", "str2", false, 0);
    testString.replace("str1", "str2", false);
    testString.replace("str1", "str2");

Можно убрать значения по умолчанию (сделав параметры обязательными), или поменять значения по умолчанию.
48K
10 декабря 2009 года
Akord
20 / / 06.12.2009
Цитата: Ghox
Какие-то трудности с этим - не знаете как сделать?


Да, у меня не получается =/ Вроде бы понимаю, но видимо не до конца.
Насчет надо-не надо, я думал, есть какие-то правила хорошего тона, т.е. раз уж все операторы перегружены, то и этот нужно)


Цитата: Ghox
о параметрах вызова


Спасибо, что объяснили. Меня смущали значения, установленные по умолчанию.

12K
11 декабря 2009 года
Ghox
297 / / 26.07.2009
Цитата: Akord
Да, у меня не получается =/ Вроде бы понимаю, но видимо не до конца.


Можно просто добавить видоизмененную версию оператора, в которой вместо аргуиента char* передается аргумент string:

 
Код:
string string::operator+(const string& s)
{
    char * temp = new char[strlen(p->s) + strlen(s.p->s) + 1];
    strcpy(temp, p->s);
    strcat(temp, s.p->s);
    string result(temp);
    delete[] temp;
    return result;
}

А можно по-другому (аналогично перегруженным find и replace из моих предыдущих вариантов) - внутри новой версии оператора вызывать (для получения результата) оператор + который был ранее создан для аргумента char*:
 
Код:
string string::operator+(const string& s)
{
    return operator+(s.p->s);
}

Цитата: Akord
Насчет надо-не надо, я думал, есть какие-то правила хорошего тона, т.е. раз уж все операторы перегружены, то и этот нужно)


Нужно ли или нет перегружать оператор для класса для разных типов аргумента оператора - зависит от класса (его конструкции и назначения), для которого пишется функция-оператор. Иногда это бывает полезно (как, похоже, в вашем случае), а иногда - не имеет смысла.

48K
11 декабря 2009 года
Akord
20 / / 06.12.2009
Большое спасибо! Вы очень мне помогли и по ходу я многое узнал.
Извините за беспокойство.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог