166 lines
6.8 KiB
C++
166 lines
6.8 KiB
C++
|
/*
|
|||
|
|
|||
|
Создадим строку, которая при создании (т.е в конструкторе) будет автоматически выделять необходимую память в Куче.
|
|||
|
В чём-то реализация этой строки будет похожа на реализацию динамического массива из прошлого семестра.
|
|||
|
|
|||
|
У класса строки 3 поля:
|
|||
|
|
|||
|
mSize - размер - количество символов в строке (без учёта \0)
|
|||
|
mCapacity - вместимость - количество выделенной памяти в Куче
|
|||
|
mpData - указатель на выделенную память в Куче. В этой памяти строка будет иметь такой же вид, как и строка языка C.
|
|||
|
В частности она будет иметь символ '\0' на конце.
|
|||
|
Символ '\0' на конце оставим, чтобы было удобно конвертировать нашу строку в строку в стиле C.
|
|||
|
|
|||
|
|
|||
|
Размер и вместимость это разные величины.
|
|||
|
|
|||
|
Например, для хранения строки "Cat" может быть выделено памяти под 10 символов, хоть и под эту строку было бы достаточно всего 4.
|
|||
|
Представьте, что у вас есть длинная строка и вы хотите удалить последний символ в ней.
|
|||
|
Если бы мы не хранили вместимость, а всегда выделяли памяти в притык, то в этом простом случае нам бы пришлось
|
|||
|
перевыделять память и копировать всю строку в новую память.
|
|||
|
Если же мы храним вместимость, то достаточно всего лишь уменьшить размер на 1 и поставит \0 в новый конец строки.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Теперь создадим конструктор, который будет выделять память и заполнять его нужным образом
|
|||
|
|
|||
|
Конструктор String(const char* str) конструирует нашу строку из строки в стиле C.
|
|||
|
Принимаем на вход именно константную строку, так как в этом случае в конструктор можно будет
|
|||
|
передать как константные, так и неконстантые строки.
|
|||
|
Если бы мы написали так String(char* str) , то в конструктор нельзя было бы передать константные строки.
|
|||
|
|
|||
|
|
|||
|
В строках:
|
|||
|
|
|||
|
size_t i = 0;
|
|||
|
while (str[i] != '\0')
|
|||
|
i++;
|
|||
|
mSize = i;
|
|||
|
mCapacity = i + 1;
|
|||
|
|
|||
|
мы находим размер переданной строки (strlen не используем, чтобы не связываться со старой библиотекой)
|
|||
|
Вместимость на 1 больше, так как нужно учесть память под символ /0
|
|||
|
|
|||
|
|
|||
|
В строке:
|
|||
|
|
|||
|
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
|
|||
|
|
|||
|
выделяем необходимую память
|
|||
|
|
|||
|
|
|||
|
В строках:
|
|||
|
|
|||
|
for (size_t i = 0; str[i] != '\0'; i++)
|
|||
|
mpData[i] = str[i];
|
|||
|
mpData[mSize] = '\0';
|
|||
|
|
|||
|
копируем содержимое переданной строки в только что выделенную память.
|
|||
|
|
|||
|
|
|||
|
Другие методы класса String:
|
|||
|
|
|||
|
getSize - возвращает размер строки
|
|||
|
getCapacity - возвращает вместимость строки
|
|||
|
cStr - возвращает строку в стиле C, то есть указатель на массив из char-ов с конечным символом \0
|
|||
|
*/
|
|||
|
|
|||
|
#include <iostream>
|
|||
|
#include <cstdlib>
|
|||
|
using std::cout, std::endl, std::size_t;
|
|||
|
|
|||
|
|
|||
|
class String
|
|||
|
{
|
|||
|
private:
|
|||
|
|
|||
|
size_t mSize;
|
|||
|
size_t mCapacity;
|
|||
|
char* mpData;
|
|||
|
|
|||
|
public:
|
|||
|
|
|||
|
|
|||
|
String(const char* str)
|
|||
|
{
|
|||
|
size_t i = 0;
|
|||
|
while (str[i] != '\0')
|
|||
|
i++;
|
|||
|
mSize = i;
|
|||
|
mCapacity = i + 1;
|
|||
|
|
|||
|
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
|
|||
|
|
|||
|
for (size_t i = 0; str[i] != '\0'; i++)
|
|||
|
mpData[i] = str[i];
|
|||
|
mpData[mSize] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
size_t getSize() const
|
|||
|
{
|
|||
|
return mSize;
|
|||
|
}
|
|||
|
|
|||
|
size_t getCapacity() const
|
|||
|
{
|
|||
|
return mCapacity;
|
|||
|
}
|
|||
|
|
|||
|
const char* cStr() const
|
|||
|
{
|
|||
|
return mpData;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
std::ostream& operator<<(std::ostream& out, const String& s)
|
|||
|
{
|
|||
|
out << s.cStr();
|
|||
|
return out;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int main()
|
|||
|
{
|
|||
|
String a = "Cat";
|
|||
|
String b = "Dog";
|
|||
|
String c = "Lion";
|
|||
|
|
|||
|
cout << a << endl << b << endl << c << endl;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
Задание:
|
|||
|
|
|||
|
1) Создайте конструктор String(), который будет создавать пустую строку
|
|||
|
(mSize = 0, mCapacity = 1, строка mpData содержит в себе 1 символ ('\0'))
|
|||
|
|
|||
|
Конструктор, который не принимает аргументов называется конструктором по умолчанию
|
|||
|
|
|||
|
|
|||
|
2) Создайте конструктор String(size_t n, char a), который будет создавать строку из n символов a
|
|||
|
(mSize = n, mCapacity = n + 1, строка mpData содержит в себе n + 1 символ (n раз a и '\0'))
|
|||
|
|
|||
|
|
|||
|
2) Создайте конструктор String(const String& s), который будет создавать строку String из другой строки String
|
|||
|
(mSize = s.mSize, mCapacity = s.mCapacity, строка mpData содержит в себе копию строки s.mpData)
|
|||
|
|
|||
|
Конструктор, который создаёт объект по другому объекту такого же типа называется конструктором копирования.
|
|||
|
|
|||
|
|
|||
|
Протестируйте эти конструкторы:
|
|||
|
String a;
|
|||
|
cout << a << endl;
|
|||
|
|
|||
|
String b(10, 'q');
|
|||
|
cout << b << endl;
|
|||
|
|
|||
|
String c("Cat");
|
|||
|
cout << c << endl;
|
|||
|
|
|||
|
String d(c);
|
|||
|
cout << d << endl;
|
|||
|
*/
|