This commit is contained in:
nihonium 2022-09-14 19:05:27 +03:00
parent 46d1c64684
commit ab6732eded
Signed by: nihonium
GPG key ID: 0251623741027CFC
98 changed files with 10319 additions and 0 deletions

View file

@ -0,0 +1,45 @@
/*
Создадим свою строку
Один из самых главных недостатков языка C это работа со строками.
Строки в языке C это просто массивы элементов типа char
char str[100]; или char* p = malloc(100);
В языке C работать со строками очень неудобно по многим причинам:
- Нужно постоянно следить за тем, чтобы строка умещалась в памяти, которая под нею выделена.
- Строку можно выделить на Стеке, используя обычный массив, и тогда её вместимость нельзя будет увеличить,
а можно выделить в Куче, но тогда придётся самостоятельно выделять и освобождать память
и следить, чтобы не произошли утечки памяти.
- Строки нельзя просто копировать, сравнивать, складывать и т. д. Для этого нужно использовать
специальные функции типа strcpy и другие функции из библиотеки <string.h>.
Создадим же удобный класс строки
Такой чтобы можно было удобно создавать строки, приравнивать, складывать и сравнивать.
Не заботясь о выделении/удалении памяти, и о том, что строка помещается в выделенную память.
Чтобы можно было писать вот такой код:
String a = "Cat";
String b = "Dog";
cout << a << " " << b << endl;
String c = "Mouse";
c = a + b;
c += "Bear";
if (c == "CatDogBear")
cout << "Yes" << endl;
c = a;
cout << c << endl;
(String в переводе с английского это Строка)
*/
int main() {}

View file

@ -0,0 +1,165 @@
/*
Создадим строку, которая при создании (т.е в конструкторе) будет автоматически выделять необходимую память в Куче.
В чём-то реализация этой строки будет похожа на реализацию динамического массива из прошлого семестра.
У класса строки 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;
*/

View file

@ -0,0 +1,104 @@
#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)
{
cout << "Construtor from const char*" << endl;
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';
}
String()
{
cout << "Default Construtor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
mpData[0] = '\0';
}
String(size_t n, char a)
{
cout << "Construtor n equal characters" << endl;
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
String(const String& s)
{
cout << "Copy Constructor" << endl;
mSize = s.mSize;
mCapacity = s.mCapacity;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[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& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a;
cout << a << endl << endl;
String b(10, 'q');
cout << b << endl << endl;
String c = "Cat";
cout << c << endl << endl;
String d(c);
cout << c << endl << endl;
}

View file

@ -0,0 +1,109 @@
/*
Делегирующий конструктор
В разных конструкторах может быть повторяющийся код.
Повторений кода иногда можно избежать если писать один конструктор на основе уже написанного.
Это можно сделать с помощью синтаксиса так называемого делегирующего конструктора
После объявления конструктора, но перед его телом можно написать двоеточие и вызвать другой конструктор
Например:
String() : String("")
{
cout << "Default Constructor" << endl;
}
Этот конструктор сначала вызовет конструктор String(const char* str) с аргументом "" (то есть пустой строкой)
а потом исполнит тело данного коструктора (в данном случае напечатает Default Constructor).
*/
#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)
{
cout << "Constructor" << endl;
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';
}
String() : String("")
{
cout << "Default Constructor" << endl;
}
String(const String& s) : String(s.cStr())
{
cout << "Copy Constructor" << endl;
}
size_t getSize() const
{
return mSize;
}
size_t getCapacity() const
{
return mCapacity;
}
const char* cStr() const
{
return mpData;
}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a;
cout << "a = " << a << endl << endl;
String b = "Cat";
cout << "b = " << b << endl << endl;
String c(b);
cout << "c = " << c << endl << endl;
}
/*
Задача:
Попробуйте понять без запуска, что напечатает данная программа
*/

View file

@ -0,0 +1,113 @@
/*
В конструкторе мы выделили память с malloc, но нигде в программе её не освободили
Соответственно, в предыдущей программе у нас есть очень серьёзная ошибка - утечка памяти.
Где же нужно освобождать память?
Если память была выделена в конструкторе при создании объекта, то выделять её нужно при удалении объекта.
Для того, чтобы испольнить ваш код при удалении объекта существует специальный метод, который называется Деструктор.
Деструктор - это специальный метод, который вызывается тогда, когда объект уничтожается
Объекты, созданные на стеке удаляются при выходе из области видимости
Синтаксис деструктора такой:
~String()
{
...
}
*/
#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)
{
cout << "Constructor of " << str << endl;
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';
}
~String()
{
cout << "Destructor of " << mpData << endl;
std::free(mpData);
}
size_t getSize() const
{
return mSize;
}
size_t getCapacity() const
{
return mCapacity;
}
const char* cStr() const
{
return mpData;
}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Dog";
if (true)
{
String c = "Lion";
}
String c = "Bear";
}
/*
Задание:
1) Что напечатает данная программа?
В каком порядке вызовутся конструкторы
2) Если создать строку String в цикле, то будут ли каждую итерацию вызываться конструкторы и деструкторы?
for (int i = 0; i < 10; ++i)
{
String s = "Elephant";
}
*/

View file

@ -0,0 +1,94 @@
/*
Оператор сложения
Оператор сложения для строк должен принимать 2 строки и возвращать новую строку, равную результату конкатенации двух строк
Если строка a = "Cat" , а строка b = "Mouse" , то их конкатенация это a + b = "CatMouse"
Оператор сложения должен принимать свои аргументы по константной ссылке
по ссылке, чтобы не копировать объект лишний раз при передаче в функцию
по константной, потому что мы не будем менять принимаемые объекты внутри функции
То есть прототип оператора сложения, если его делать с помощью обычной функции, должен выглядеть так:
String operator+(const String& a, const String& b)
Прототип оператора сложения, если его делать с помощью метода класса String, должен выглядеть так:
String operator+(const String& b) const
*/
#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)
{
cout << "Constructor of " << str << endl;
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';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
cout << "Destructor of " << mpData << endl;
std::free(mpData);
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Mouse";
cout << a + b << endl;
}
/*
Задание:
1) Написать оператор сложения для строки String в виде свободной функции
В этом случае эту функцию нужно сделать дружественной классу String,
чтобы она имела доступ к приватным полям класса
2) Написать оператор сложения для строки String в виде метода класса String
*/

View file

@ -0,0 +1,86 @@
#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';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
friend String operator+(const String& a, const String& b);
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
String operator+(const String& a, const String& b)
{
String result;
result.mSize = a.mSize + b.mSize;
result.mCapacity = result.mSize + 1;
result.mpData = (char*)std::malloc(sizeof(char) * result.mCapacity);
for (size_t i = 0; i < a.mSize; ++i)
result.mpData[i] = a.mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[a.mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
int main()
{
String a = "Cat";
String b = "Mouse";
cout << a + b << endl;
}

View file

@ -0,0 +1,86 @@
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
String operator+(const String& b)
{
String result;
result.mSize = mSize + b.mSize;
result.mCapacity = result.mSize + 1;
result.mpData = (char*)std::malloc(sizeof(char) * result.mCapacity);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
~String()
{
std::free(mpData);
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
friend String operator+(const String& a, const String& b);
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Mouse";
cout << a + b << endl;
}

View file

@ -0,0 +1,126 @@
/*
Оператор присваивания
Оператор присваивания можно сделать только в виде метода
Такой метод должен
- принимать один аргумент - это правый аргумент оператора присваивания,
- менять объект, вызвавший оператор (то есть левый аргумент оператора присваивания)
- возвращать ссылку на объект, вызвавший оператор (то есть объект слева от оператора присваивания)
Почему оператор присваивания должен возвращать ссылку на левый аргумент?
Чтобы оператор присваивания работал аналогично тому как работает оператор присваивания для обычных типов
Рассмотрим следующий пример:
int a, b, c;
a = b = c = 123; // все переменные станут равны 123, операторы выполняются справа налево
(a = 1) = 2; // a станет равной 2
Мы хотим, чтобы и такой код работал:
String a, b, c;
a = b = c = "Cat";
(a = "Dog") = "Mouse";
Прототип оператора присваивания как метода класса String должен выглядеть так:
String& operator=(const String& b)
*/
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
// Ваш код нужно написать здесь
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Mouse";
String c;
a = b;
cout << a << endl;
a = b = c = "Elephant";
cout << a << endl;
cout << b << endl;
cout << c << endl;
(a = "Dog") = "Axolotl";
cout << a << endl;
a = a;
cout << a << endl;
}
/*
Задание:
1) Написать оператор присваивания для строки String в виде метода класса String
Не забудьте учесть случай:
String a = "Cat";
a = a;
*/

View file

@ -0,0 +1,92 @@
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Mouse";
String c;
a = b;
cout << a << endl;
a = b = c = "Elephant";
cout << a << endl;
cout << b << endl;
cout << c << endl;
(a = "Dog") = "Axolotl";
cout << a << endl;
}

View file

@ -0,0 +1,132 @@
/*
Оператор присваивания сложения +=
Очень похож на оператор присваивания, разница только в том, каким станет левый операнд после применения этого оператора
К левому операнду в этом случае должна прибавиться копия правого оператора
Если a = "Cat" , b = "Dog" , то после применения a += b строка a будет равна "CatDog"
Прототип оператора присваивания сложения как метода класса String должен выглядеть так:
String& operator+=(const String& b)
*/
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String operator+(const String& b)
{
String result;
result.mSize = mSize + b.mSize;
result.mCapacity = result.mSize + 1;
result.mpData = (char*)std::malloc(sizeof(char) * result.mCapacity);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String& operator+=(const String& right)
{
// Ваш код нужно написать здесь
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Mouse";
String b = "Elephant";
b += a;
cout << b << endl;
}
/*
Задание:
1) Написать оператор присваивания сложения для строки String в виде метода класса String
Подсказка: можно использовать уже написанные операторы, чтобы реализовать этот
*/

View file

@ -0,0 +1,110 @@
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String operator+(const String& b)
{
String result;
result.mSize = mSize + b.mSize;
result.mCapacity = result.mSize + 1;
result.mpData = (char*)std::malloc(sizeof(char) * result.mCapacity);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String& operator+=(const String& right)
{
*this = *this + right;
return *this;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Mouse";
String b = "Elephant";
b += a;
cout << b << endl;
}

View file

@ -0,0 +1,122 @@
/*
По решению предыдущего занятия понятно, что операторы + = и += взаимосвязаны.
Если реализованы операторы + и = можно, используя их, реализовать оператор +=
Если реализованы операторы = и += можно, используя их, реализовать оператор +
*/
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String& operator+=(const String& right)
{
if (mCapacity < mSize + right.mSize + 1)
{
mCapacity = mSize + right.mSize + 1;
char* pNewData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
pNewData[i] = mpData[i];
std::free(mpData);
mpData = pNewData;
}
for (size_t i = 0; i < right.mSize; ++i)
mpData[mSize + i] = right.mpData[i];
mSize += right.mSize;
mpData[mSize] = '\0';
return *this;
}
String operator+(const String& b)
{
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Mouse";
String b = "Elephant";
cout << a + b << endl;
}
/*
Задача:
1) Напишите оператор + , используя операторы = и +=
*/

View file

@ -0,0 +1,108 @@
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String& operator+=(const String& right)
{
if (mCapacity < mSize + right.mSize + 1)
{
mCapacity = mSize + right.mSize + 1;
char* pNewData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
pNewData[i] = mpData[i];
std::free(mpData);
mpData = pNewData;
}
for (size_t i = 0; i < right.mSize; ++i)
mpData[mSize + i] = right.mpData[i];
mSize += right.mSize;
mpData[mSize] = '\0';
return *this;
}
String operator+(const String& b)
{
String result = *this;
result += b;
return result;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Mouse";
String b = "Elephant";
cout << a + b << endl;
}

View file

@ -0,0 +1,120 @@
/*
Операторы сравнения == != > >= < <=
К строкам можно применять операторы сравнения.
Очевидно, когда строки равны: должны быть равны размеры строк (mSize) и все символы от 0 до mSize
При этом вместимость (mCapacity) у равных строк может отличаться
Как сравнивать строки на больше/меньше? В этом случае сравниваем лексикографически, то есть, по алфавиту.
То слово, которое находилось бы в орфографическом словаре позже и будет большим.
Например, "Cat" > "Camel" так как первые 2 буквы совпадают, а третья буква у слова Cat идёт дальше по алфавиту
Более точное сравнение такое: мы сравниваем посимвольно до первого несовпадающего символа
Если мы нашли первые несовпадающий символ и не дошли до конца в обоих строках, то та строка будет больше,
у которой этот символ больше.
*/
#include <iostream>
#include <iomanip>
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
cout << std::boolalpha;
String a = "Cat";
String b = "Camel";
cout << (a > b) << endl;
cout << (a < b) << endl;
cout << (a == b) << endl;
cout << (a == a) << endl;
String c = "Catharsis";
cout << (a > c) << endl;
cout << (a < c) << endl;
cout << (a == c) << endl;
cout << (a != c) << endl;
}
/*
Задача:
1) Напишите операторы == != > >= < <= для класса String
Подсказка: можно использовать уже написанные сравнения
Например, если вы написали оператор > , то очень просто написать оператор <= , используя оператор >
*/

View file

@ -0,0 +1,140 @@
#include <iostream>
#include <iomanip>
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
bool operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool operator<=(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool operator!=(const String& right) const
{
return !(*this == right);
}
bool operator>(const String& right) const
{
return !(*this <= right);
}
bool operator>=(const String& right) const
{
return !(*this < right);
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
cout << std::boolalpha;
String a = "Cat";
String b = "Camel";
cout << (a > b) << endl;
cout << (a < b) << endl;
cout << (a == b) << endl;
cout << (a == a) << endl;
String c = "Catharsis";
cout << (a > c) << endl;
cout << (a < c) << endl;
cout << (a == c) << endl;
cout << (a != c) << endl;
}

View file

@ -0,0 +1,122 @@
/*
Операторы индексации []
Чтобы получить доступ к одному символу у строки в стиле C можно использовать оператор индексации (квадратные скобочки).
Хотелось бы иметь такую же возможность и для нашей строки.
Для этого можно перегрузить оператор индексации:
char& operator[](size_t i)
Этот оператор вызавется при взятии символа по индексу, например, если a это строка типа String,
a[i] будет восприниматься компилятором как a.operator[](i)
Оператор индексации должен возвращать ссылку на символ, чтобы можно было менять соответствующий символ
a[i] = 'A';
*/
#include <iostream>
#include <iomanip>
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
cout << a[0] << endl;
cout << a[2] << endl;
cout << a[4] << endl;
cout << a.at(0) << endl;
cout << a.at(2) << endl;
cout << a.at(4) << endl;
}
/*
Задача:
1) Напишите оператор индексации для класса String
2) Напишите метод at, который будет работать аналогично оператору индексации, только с тем отличием, что
если на вход приходит неправильный индекс (т. е. индекс >= mSize), то метод at должен печатать сообщение
об ошибке и завершать программу.
Для завершения программы используйте функцию std::exit(1) из библиотеки <cstdlib>.
*/

View file

@ -0,0 +1,102 @@
#include <iostream>
#include <iomanip>
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
char& at(size_t i)
{
if (i >= mSize)
{
cout << "Error! Index is out of bounds." << endl;
std::exit(1);
}
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
cout << a[0] << endl;
cout << a[2] << endl;
cout << a[4] << endl;
cout << a.at(0) << endl;
cout << a.at(2) << endl;
cout << a.at(4) << endl;
}

View file

@ -0,0 +1,145 @@
/*
Напишем ещё 2 очень полезных метода:
1) reserve - увеличивает вместимость строки, на вход методу передаётся новая вместмость
если новая вместимость меньше старой, то ничего не происходит (вместимость не уменьшается)
размер и содержимое строки не меняется
2) resize - изменяет размер строки, на вход методу передаётся новый размер
если новый размер меньше старого, то строка усекается
при необходимости увеличивает вместимость
Используя эти два метода можно немного упростить код для операторов сложения и присваивания.
Эти методы могут быть полезны и для программиста, который будет работать с нашей строкой, поэтому сделаем их публичными.
*/
#include <iostream>
#include <iomanip>
#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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Dog";
cout << a.getCapacity() << endl;
a.reserve(10);
cout << a.getCapacity() << endl;
cout << a + b << endl;
String c = "Sapere Aude";
cout << c << endl;
c.resize(6);
cout << c << endl;
}

View file

@ -0,0 +1,134 @@
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout, std::cin, 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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = "Dog";
cout << a.getCapacity() << endl;
a.reserve(10);
cout << a.getCapacity() << endl;
cout << a + b << endl;
String c = "Sapere Aude";
cout << c << endl;
c.resize(6);
cout << c << endl;
}

View file

@ -0,0 +1,166 @@
/*
Считывание строки с экрана
Помимо удобной печати на экран с помощью объекта std::cout, хотелось бы добавить удобное считываие строки
с помощью объекта std::cin.
Для этого нужно перегрузить оператор >> с объектами типа std::istream и String, то есть написать функцию:
std::istream& operator>>(std::istream& in, String& str)
Эта функция должна считывать символы из стандартного входа и добавлять в строку
Основная проблема в том, что мы не знаем сколько символов нужно считать, поэтому нужно считывать
посимвольно и добавлять символы по одному в строку пока не встретим пробельный символ (' ' или '\n' или '\t')
Для упрощения программы можно написать дополнительные методы
void clear() - метод, который будет очищать строку
mSize = 0, mCapacity = 1, строка по адресу mpData равна "\0"
void addCharacter(char c) - добавляет символ в конец строки
если у строки не хватает вместимости, то удваивает вместимость.
Для того, чтобы считать символ из стандартного входа можно использовать метод get класса istream
Этот метод возвращает следующий символ из стандартного входа
char x = cin.get();
*/
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout, std::cin, 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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a, b;
cin >> a >> b;
cout << a + b;
a.addCharacter('!');
cout << a << endl;
}
/*
Задача:
1) Напишите метод clear.
2) Напишите метод addCharacter.
3) Напишите перегруженный оператор << для считывания строки с экрана.
*/

View file

@ -0,0 +1,158 @@
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout, std::cin, 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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
char& operator[](size_t i)
{
return mpData[i];
}
void clear()
{
std::free(mpData);
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
mpData[0] = '\0';
}
void addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
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;
}
std::istream& operator>>(std::istream& in, String& s)
{
s.clear();
while (true)
{
char x = in.get();
if (x == ' ' || x == '\n' || x == '\t')
break;
s.addCharacter(x);
}
return in;
}
int main()
{
String a, b;
cin >> a >> b;
cout << a + b << endl;
a.addCharacter('!');
cout << a << endl;
}

View file

@ -0,0 +1,262 @@
/*
Собираем все методы вместе. Получилась строка, которой можно удобно пользоваться и не задумываться о выделении памяти.
*/
#include <iostream>
#include <cstdlib>
using std::cout, std::cin, 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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
String(size_t n, char a)
{
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
String& operator+=(const String& right)
{
*this = *this + right;
return *this;
}
bool operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool operator<=(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool operator!=(const String& right) const
{
return !(*this == right);
}
bool operator>(const String& right) const
{
return !(*this <= right);
}
bool operator>=(const String& right) const
{
return !(*this < right);
}
char& operator[](size_t i)
{
return mpData[i];
}
char& at(size_t i)
{
if (i >= mSize)
{
cout << "Error! Index is out of bounds." << endl;
std::exit(1);
}
return mpData[i];
}
void clear()
{
std::free(mpData);
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
mpData[0] = '\0';
}
void addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
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;
}
std::istream& operator>>(std::istream& in, String& s)
{
s.clear();
while (true)
{
char x = in.get();
if (x == ' ' || x == '\n' || x == '\t')
break;
s.addCharacter(x);
}
return in;
}
int main()
{
String a = "Mouse";
String b;
cin >> b;
String c = b;
if (a + c == "MouseLion")
cout << "Yes" << endl;
else
cout << "No" << endl;
if (a > "Mice")
cout << "Yes" << endl;
else
cout << "No" << endl;
c[0] = 'P';
cout << c << endl;
c += a;
cout << c << endl;
c = c + String(10, 'q');
cout << c << endl;
}
/*
Задача:
1) Напищите программу, которая будет считывать слова (используйте cin) в бесконечном цикле и каждый
раз печатать сумму всех слов. Например, если пользователь ввёл Hello, то программа должна напечатать
Hello и запросить следующее слово. Если затем пользователь введёт World, то программа должна будет
напечатать HelloWorld и запросить следуещее слово и так далее.
Программа должна останавливаться если пользователь ввёл слово "quit".
*/

View file

@ -0,0 +1,233 @@
#include <iostream>
#include <cstdlib>
using std::cout, std::cin, 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]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String() : String("") {}
String(const String& s) : String(s.cStr()) {}
String(size_t n, char a)
{
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
~String()
{
std::free(mpData);
}
void reserve(size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
String& operator+=(const String& right)
{
*this = *this + right;
return *this;
}
bool operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool operator<=(const String& right) const
{
size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool operator!=(const String& right) const
{
return !(*this == right);
}
bool operator>(const String& right) const
{
return !(*this <= right);
}
bool operator>=(const String& right) const
{
return !(*this < right);
}
char& operator[](size_t i)
{
return mpData[i];
}
char& at(size_t i)
{
if (i >= mSize)
{
cout << "Error! Index is out of bounds." << endl;
std::exit(1);
}
return mpData[i];
}
void clear()
{
std::free(mpData);
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
mpData[0] = '\0';
}
void addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
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;
}
std::istream& operator>>(std::istream& in, String& s)
{
s.clear();
while (true)
{
char x = in.get();
if (x == ' ' || x == '\n' || x == '\t')
break;
s.addCharacter(x);
}
return in;
}
int main()
{
String all;
String nextWord;
while (true)
{
cin >> nextWord;
if (nextWord == "quit")
break;
all += nextWord;
cout << all << endl;
}
}

View file

@ -0,0 +1,142 @@
/*
Рассмотрим при каких условиях происходит вызов того или иного метода.
Для этого будем использовать класс String, в котором была добавлена печать на экран для конструкторов,
деструктора и оператора присваивания.
Например, конструктор по умолчанию будет печатать Default Constructor и т. д.
*/
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = a;
}
/*
Задачи:
1) Какие методы вызовутся в строке
String a = "Cat";
Выберите один из вариантов:
а) Только конструктор из const char*
б) Только оператор присваивания
в) И конструктор из const char* и оператор присваивания
2) Какие методы вызовутся в строке
String b = a;
Выберите один из вариантов:
а) Только конструктор копирования
б) Только оператор присваивания
в) И конструктор копирования и оператор присваивания
3) Проверьте ваши догадки скомпилировав и запустив программу
*/

View file

@ -0,0 +1,121 @@
/*
Рассмотрим при каких условиях происходит вызов того или иного метода.
Для этого будем использовать класс String, в котором была добавлена печать на экран для конструкторов,
деструктора и оператора присваивания.
Например, конструктор по умолчанию будет печатать Default Constructor и т. д.
*/
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String c;
c = a;
}
/*
Задачи:
1) Какие методы класса String вызовутся в данной программе.
2) Проверьте ваши догадки, скомпилировав и запустив программу
*/

View file

@ -0,0 +1,36 @@
/*
Решения:
1) String a = "Cat";
Будет вызван только конструктор из const char*
2) String b = a;
Будет вызван только конструктор копирования
Несмотря на то, что в этих выражениях присутствует символ = оператор присваивания в этих случаях не вызывается.
3) String c;
c = a;
Будет вызван конструктор по умолчанию в строке String c;
А потом будет вызван оператор присваивания в строке c = a;
Получается символ = может использоваться для обозначения двух разных вещей: инициализации и присваивания.
String a = "Cat"; // Инициализация строкой "Cat" (вызов коструктора от const char*)
String b = a; // Инициализация объектом a (вызов коструктора копирования)
String c; // Инициализация по умолчанию (вызов конструктора по умолчанию)
c = a; // Присваивание (вызов метода operator=)
*/

View file

@ -0,0 +1,135 @@
/*
Посмотрим какие особые методы вызываются при передаче объекта в функцию.
*/
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
void print(String s)
{
cout << s << endl;
}
int main()
{
String a = "Cat";
print(a);
}
/*
Задачи:
1) Какие методы класса String вызовутся в данной программе.
2) Проверьте ваши догадки скомпилировав и запустив программу
3) Что если мы будем передавать объект String в функцию print не по значению, а по ссылке, то есть изменим
функцию print на следующую:
void print(const String& s)
{
cout << s << endl;
}
Какие методы будут вызваны теперь?
*/

View file

@ -0,0 +1,64 @@
/*
Решения:
1) В случае:
void print(String s)
{
cout << s << endl;
}
int main()
{
String a = "Cat";
print(a);
}
Вызовутся следующие методы:
1) Конструктор строки из "Cat"
2) При передаче объекта в функцию по значению, он должен быть скопирован.
Соответственно при вызове print(a) объект a должен скопироваться в объект s функции print.
Для обычных типов вроде int тут бы произошло побайтовое копирование, но для классов вызывается конструктор копирования.
3) Внутри функции print объект s печатается на экран. Затем мы выходим из функции print и уничтожаем все локальные объекты этой функции.
Соответственно вызовется деструктор для объекта s.
4) Затем мы выходим из функции main и уничтожаем все объекты, локальные для функции main.
Соответственно вызовется деструктор для объекта a.
3) В случае:
void print(const String& s)
{
cout << s << endl;
}
int main()
{
String a = "Cat";
print(a);
}
Вызовутся следующие методы:
1) Конструктор строки из "Cat"
При передаче объекта в функцию по ссылке, этот объект в функцию не копируется.
Поэтому никаких конструкторов копирования не вызывается.
2) Деструктор для строки a из функии main.
Получается, что обычно передавать объекты в функции более эффективно по ссылке, а не по значению.
*/

View file

@ -0,0 +1,131 @@
/*
Особые методы при передачах в функцию
Посмотрим какие особые методы вызываются при передаче объекта в функцию
*/
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
void changeFirstLetter(String s)
{
s[0] = 'B';
}
int main()
{
String a = "Cat";
cout << a << endl;
changeFirstLetter(a);
cout << a << endl;
}
/*
Задачи:
1) Какие методы класса String вызовутся в данной программе.
2) Проверьте ваши догадки скомпилировав и запустив программу
3) Функция changeFirstLetter должна была менять первую букву нашей строки на букву 'B', но это не происходит и
строка a после вызова changeFirstLetter(a) остаётся неизменной.
Почему это происходит и как изменить функцию changeFirstLetter чтобы она меняла первую букву переданной строки.
*/

View file

@ -0,0 +1,136 @@
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
void changeFirstLetter(String& s)
{
s[0] = 'B';
}
int main()
{
String a = "Cat";
cout << a << endl;
changeFirstLetter(a);
cout << a << endl;
}
/*
Решение:
В такую функцию:
void changeFirstLetter(String s)
{
s[0] = 'B';
}
строка передавалась по значению и, следовательно, происходило копирование этой строки в объект s функции changeFirstLetter.
Функция changeFirstLetter меняла первую букву копии нашей строки, но оригинальная строка не менялась.
Для того, чтобы функция changeFirstLetter меняла оригинальную строку ей нужно передавать объект не по значению, а по ссылке вот так:
void changeFirstLetter(String& s)
{
s[0] = 'B';
}
*/

View file

@ -0,0 +1,149 @@
/*
Различный синтаксис вызова конструкторов
*/
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a = "Cat";
String b = String("Dog");
String c("Mouse");
String d = {"Tiger"};
String e = String{"Axolotl"};
String f {"Lion"};
}
/*
Ввиду того, что язык C++ имеет длинную историю, на протяжении которой в язык добавлялись новые возможности,
в языке существует множество способов сделать одно и то же разными способами.
Один из ярких примеров этого является инициализация объекта. В этом примере создаются 6 строк. Синтаксис различается,
но в данном случае все эти строки по сути делают одно и то же: cоздают объект с помощью конструктора от const char*.
При этом не вызывается никаких конструкторов копирования или операторов присваивания.
В современном языке C++ предпочтительным способом инициализации является вариант f:
String f {"Lion"};
Задачи:
1) Что напечатает данная программа?
В каком порядке вызовутся конструкторы и в каком порядке вызовутся деструкторы?
2) Скомпилируйте программу и запустите, чтобы проверить ваши догадки.
3) Создайте 5 объектов типа String с помощью конструктора по умолчанию, используя разный синтаксис вызова конструктора.
4) Пусть есть объект x типа String:
String x = "Cat";
Создайте 6 объектов типа String с помощью конструктора копирования, используя разный синтаксис вызова конструктора.
Все новые объекты должны копировать объект x.
*/

View file

@ -0,0 +1,124 @@
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String a;
String b = String();
// String c();
String d = {};
String e = String{};
String f {};
}
/*
Аналогично есть множество вариантов синтаксиса вызова конструктора по умолчанию.
Только такой вариант вызова конструктора не работает:
String c();
Потому что в этом случае компилятор считает, что это объявление функции по имени c, которая ничего не принимает и возвращает объект типа String.
*/

View file

@ -0,0 +1,116 @@
#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)
{
cout << "String Constructor from const char* (" << str << ")" << endl;
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]; ++i)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String()
{
cout << "String Default Constructor" << endl;
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char));
mpData[0] = '\0';
}
String(const String& s)
{
cout << "String Copy Constructor (" << s.mpData << ")" << endl;
size_t i = 0;
mSize = s.mSize;
mCapacity = mSize + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i < mSize; ++i)
mpData[i] = s.mpData[i];
mpData[mSize] = '\0';
}
~String()
{
cout << "String Destructor (" << mpData << ")" << endl;
std::free(mpData);
}
String& operator=(const String& right)
{
cout << "String Assignment Operator (" << right.mpData << ")" << endl;
if (this == &right)
return *this;
mSize = right.mSize;
mCapacity = right.mCapacity;
std::free(mpData);
mpData = (char*)malloc(sizeof(char) * mCapacity);
for (size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
char& operator[](size_t i)
{
return mpData[i];
}
size_t getSize() const {return mSize;}
size_t getCapacity() const {return mCapacity;}
const char* cStr() const {return mpData;}
};
std::ostream& operator<<(std::ostream& left, const String& right)
{
left << right.cStr();
return left;
}
int main()
{
String x = "Cat";
String a = x;
String b = String(x);
String c(x);
String d = {x};
String e = String{x};
String f {x};
}