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,62 @@
/*
Раздельная компиляция.
В этой части мы вынесем весь код, связанный с нашим классом Point в отдельные файлы.
А также скомпилируем отдельно код, относящийся к нашему классу Point.
Это будет проделано в следующий примерах, а пока тут просто лежит код
класса Point из предыдущих частей.
*/
#include <iostream>
#include <iomanip>
#include <cmath>
using std::cout, std::endl;
struct Point
{
float x, y;
Point operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float norm() const
{
return std::sqrt(x * x + y * y);
}
Point operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
};
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}
int main()
{
Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,81 @@
/*
Вынос определений методов вне класса.
Методы внутри класса можно только объявить, а определить их можно вне класса.
Например, метод norm объявлен внутри класса:
float norm() const;
а определён вне класса:
float Point::norm() const
{
return std::sqrt(x * x + y * y);
}
Чтобы компилятор понимал к какому классу относится тот или иной метод,
к его имени вне класса нужно добавить название класса и два двоеточия.
Поэтому метод norm вне класса Point называется как Point::norm.
*/
#include <iostream>
#include <iomanip>
#include <cmath>
using std::cout, std::endl;
struct Point
{
float x, y;
Point operator+(Point b) const;
float norm() const;
Point operator*(float k) const;
void normalize();
};
Point Point::operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float Point::norm() const
{
return std::sqrt(x * x + y * y);
}
Point Point::operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void Point::normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}
int main()
{
Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,61 @@
/*
Перенос кода в заголовочный файл
В этом примере мы перенесли весь код, связанный с классом Point в отдельный файл point.hpp.
Файл point.hpp подключается к файлу main.cpp с помощью директивы #include в строке:
#include "point.hpp"
На самом деле директива #include делает очень простую вещь: она просто берёт всё содержимое
передаваемого ей файла и вставляет это содержимое на место директивы.
То есть в этом примере за место #include "point.hpp" подставится всё содержимое файла point.hpp.
Так как директива #include уже сама вставила файл point.hpp в файл main.cpp, то дополнительно
указывать файл point.hpp при компиляции не нужно. Скомпилировать этот пример можно так:
g++ main.cpp
Стандартные библиотеки типа iostream подключаются так же. То есть где-то в системе, в какой-то папке
хранится стандартная библиотека C++ и, соответственно, есть файл под название iostream (без расширения).
Этот файл и подставляется за место строки #include <iostream>.
Чтобы посмотреть в каких папках компилятор ищет файлы стандартной библиотеки можно скомпилировать программу так:
g++ -v main.cpp
Он напечатает множество информации о компиляции, в числе прочего пути где происходит поиск при исполнении #include.
Вы могли заметить, что стандартные библиотеки в директиве #include пишутся в треугольных скобочках, а нашу
библиотеку point.hpp мы написали в двойных кавычках. В чём разница между этими вариантами?
На самом деле разница лишь в том, в каких папках компилятор ищет данные файлы.
Если мы пишем библиотеку в треугольных скобках, то компилятор ищет её в папках стандартной библиотеки.
Если мы пишем библиотеку в кавычках, то компилятор ищет её в папках текущей директории.
Защита от двойного включения
Используя директивы #include, очень легко включить один и тот же файл 2 и более раз.
Например, в этом примере файл iostream включается 2 раза: один раз непосредственно в файле main.cpp, а второй раз
он включится после того, как включиться файл point.hpp. Внутри файла point.hpp тоже есть #include <iostream>.
Если не предпринимать никаких действий, то произойдёт ошибка, так как одинаковые функции и классы
будут повторяться в программе несколько раз.
Чтобы защититься от этой проблемы нужно в начале заголовочного файла написать директиву
#pragma once
Таким образом компилятор будет понимать, что вы не хотите включать файл более одного раза и включит только одну копию файла.
Эта директива была использовани и в файле point.hpp.
*/
#include <iostream>
#include "point.hpp"
using std::cout, std::endl;
int main()
{
Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,39 @@
#pragma once
#include <iostream>
#include <iomanip>
#include <cmath>
struct Point
{
float x, y;
Point operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float norm() const
{
return std::sqrt(x * x + y * y);
}
Point operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
};
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}

View file

@ -0,0 +1,17 @@
/*
Всё что относится к классу Point мы перенесли в отдельный файл point.hpp.
А также мы разделили объявления и определения методов в файле point.hpp.
*/
#include <iostream>
#include <iomanip>
#include <cmath>
#include "point.hpp"
using std::cout, std::endl;
int main()
{
Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,45 @@
#pragma once
#include <iostream>
struct Point
{
float x, y;
Point operator+(Point b) const;
float norm() const;
Point operator*(float k) const;
void normalize();
};
Point Point::operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float Point::norm() const
{
return std::sqrt(x * x + y * y);
}
Point Point::operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void Point::normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}

View file

@ -0,0 +1,40 @@
/*
Раздельная компиляция
Теперь мы разделим объявления и определения всех методов класса Point.
Все объявления класса Point поместим в файл point.hpp, а определения методов в файл point.cpp.
Таким образом у нас получилось 2 компилируемых файла: main.cpp и point.cpp и 1 заголовочный файл point.hpp.
При этом заголовочный файл point.hpp должен подключаться везде, где используется класс Point.
То есть в данном случае он должен подключаться и в файл main.cpp и в файл point.cpp.
Для компиляции программы нужно указать компилятору на все компилируемые файлы вот так:
g++ main.cpp point.cpp
Если это не сделать и скомпилировать только файл main.cpp, то возникнет ошибка undefined reference to norm().
Грубо говоря программа будет знать, что есть класс Point и знать его методы (так как это всё описано в point.hpp),
но любые попытки вызвать эти методы будут приводить к ошибке, так как они не были скомпилированы.
Преемущество раздельной компиляции заключается в том, что компилировать разные .cpp файлы можно поотдельности.
Представьте, что у вас огромный проект, содержащий тысячи файлов и миллионы строк кода. Такой проект может компилироваться часами.
Теперь вы сделали небольшое изменение в одном файле этого проекта. Если бы нельзя было бы компилировать файлы поотдельности,
то после любого изменения вам бы пришлось компилировать весь проект заново и ждать часы пока компиляция закончится.
К счастью, .cpp файлы можно компилировать поотдельности и, если вы сделали изменение в одном файле, то скомпилировать
потребуется только тот файл, который вы изменили.
*/
#include <iostream>
#include "point.hpp"
using std::cout, std::endl;
int main()
{
Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,35 @@
#include <iostream>
#include <iomanip>
#include <cmath>
#include "point.hpp"
Point Point::operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float Point::norm() const
{
return std::sqrt(x * x + y * y);
}
Point Point::operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void Point::normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}

View file

@ -0,0 +1,15 @@
#pragma once
#include <iostream>
struct Point
{
float x, y;
Point operator+(Point b) const;
float norm() const;
Point operator*(float k) const;
void normalize();
};
std::ostream& operator<<(std::ostream& out, Point a);

View file

@ -0,0 +1,30 @@
/*
Пространства имён
Имя Point достаточно распространённое и есть очень большая вероятность того, что при подключении нескольких библиотек
в некоторых из них тоже будет класс с именем Point. Конечно, если ничего не предпринять, это приведёт к ошибке.
Чтобы избежать ошибок, связанных с конфликтами имён, положим весь код нашего класса Point в пространство имён mipt.
Для этого обернём наш код в файлах point.hpp и point.cpp
namespace mipt
{
...
}
Теперь наш класс Point будет лежать в пространстве имён mipt.
Для его использования вне пространства имён mipt нужно писать mipt::Point (ну либо использовать using mipt::Point;)
*/
#include <iostream>
#include "point.hpp"
using std::cout, std::endl;
int main()
{
mipt::Point a = {7.2, 3.1};
cout << a.norm() << endl;
}

View file

@ -0,0 +1,40 @@
#include <iostream>
#include <iomanip>
#include <cmath>
#include "point.hpp"
namespace mipt
{
Point Point::operator+(Point b) const
{
Point result = {x + b.x, y + b.y};
return result;
}
float Point::norm() const
{
return std::sqrt(x * x + y * y);
}
Point Point::operator*(float k) const
{
Point result = {k * x, k * y};
return result;
}
void Point::normalize()
{
float normv = norm();
x /= normv;
y /= normv;
}
std::ostream& operator<<(std::ostream& out, Point a)
{
out << std::setprecision(2) << "(" << a.x << ", " << a.y << ")";
return out;
}
}

View file

@ -0,0 +1,20 @@
#pragma once
#include <iostream>
namespace mipt
{
struct Point
{
float x, y;
Point operator+(Point b) const;
float norm() const;
Point operator*(float k) const;
void normalize();
};
std::ostream& operator<<(std::ostream& out, Point a);
}

View file

@ -0,0 +1,265 @@
/*
В данной программе содержится класс String, написанный нами в одной из предыдущих частей.
Задачи:
1) Вынесите класс String в отдельный заголовочный файл string.hpp и скомпилируйте программу.
2) Вынесите объявления методов класса String в заголовочный файл string.hpp, а определения
методов в компилируемый файл string.cpp. Скомпилируйте программу.
3) Вынесите объявления методов класса String в заголовочный файл string.hpp, а определения
методов в компилируемый файл string.cpp. А также поместите весь код класса String в пространство имён mipt.
Скомпилируйте программу.
*/
#include <iostream>
#include <cstdlib>
class String
{
private:
std::size_t mSize;
std::size_t mCapacity;
char* mpData;
public:
String(const char* str)
{
std::size_t i = 0;
while (str[i] != '\0')
i++;
mSize = i;
mCapacity = i + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::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::size_t n, char a)
{
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
~String()
{
std::free(mpData);
}
void reserve(std::size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(std::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 (std::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 (std::size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (std::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;
std::size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
std::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
{
std::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[](std::size_t i)
{
return mpData[i];
}
char& at(std::size_t i)
{
if (i >= mSize)
{
std::cout << "Error! Index is out of bounds." << std::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);
}
std::size_t getSize() const {return mSize;}
std::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;
std::cin >> b;
String c = b;
if (a + c == "MouseLion")
std::cout << "Yes" << std::endl;
else
std::cout << "No" << std::endl;
if (a > "Mice")
std::cout << "Yes" << std::endl;
else
std::cout << "No" << std::endl;
c[0] = 'P';
std::cout << c << std::endl;
c += a;
std::cout << c << std::endl;
c = c + String(10, 'q');
std::cout << c << std::endl;
}

View file

@ -0,0 +1,37 @@
#include <iostream>
#include <cstdlib>
#include "string.hpp"
using std::cout, std::cin, std::endl;
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;
}

View file

@ -0,0 +1,214 @@
#include <iostream>
#include <cstdlib>
class String
{
private:
std::size_t mSize;
std::size_t mCapacity;
char* mpData;
public:
String(const char* str)
{
std::size_t i = 0;
while (str[i] != '\0')
i++;
mSize = i;
mCapacity = i + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::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::size_t n, char a)
{
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
~String()
{
std::free(mpData);
}
void reserve(std::size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void resize(std::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 (std::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 (std::size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (std::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;
std::size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool operator<(const String& right) const
{
std::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
{
std::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[](std::size_t i)
{
return mpData[i];
}
char& at(std::size_t i)
{
if (i >= mSize)
{
std::cout << "Error! Index is out of bounds." << std::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);
}
std::size_t getSize() const {return mSize;}
std::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;
}

View file

@ -0,0 +1,39 @@
/*
Компиляция:
g++ main.cpp string.cpp
*/
#include <iostream>
#include "string.hpp"
using std::cout, std::cin, std::endl;
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;
}

View file

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

View file

@ -0,0 +1,51 @@
#pragma once
#include <iostream>
#include <cstdlib>
class String
{
private:
std::size_t mSize;
std::size_t mCapacity;
char* mpData;
public:
String(const char* str);
String();
String(const String& s);
String(std::size_t n, char a);
~String();
void reserve(std::size_t capacity);
void resize(std::size_t size);
String& operator=(const String& right);
String operator+(const String& b);
String& operator+=(const String& right);
bool operator==(const String& right) const;
bool operator<(const String& right) const;
bool operator<=(const String& right) const;
bool operator!=(const String& right) const;
bool operator>(const String& right) const;
bool operator>=(const String& right) const;
char& operator[](std::size_t i);
char& at(std::size_t i);
void clear();
void addCharacter(char c);
std::size_t getSize() const;
std::size_t getCapacity() const;
const char* cStr() const;
};
std::ostream& operator<<(std::ostream& out, const String& s);
std::istream& operator>>(std::istream& in, String& s);

View file

@ -0,0 +1,32 @@
#include <iostream>
#include "string.hpp"
using std::cout, std::cin, std::endl;
int main()
{
mipt::String a = "Mouse";
mipt::String b;
cin >> b;
mipt::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 + mipt::String(10, 'q');
cout << c << endl;
}

View file

@ -0,0 +1,207 @@
#include <iostream>
#include <cstdlib>
#include "string.hpp"
namespace mipt {
String::String(const char* str)
{
std::size_t i = 0;
while (str[i] != '\0')
i++;
mSize = i;
mCapacity = i + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; str[i]; i++)
mpData[i] = str[i];
mpData[mSize] = '\0';
}
String::String() : String("") {}
String::String(const String& s) : String(s.cStr()) {}
String::String(std::size_t n, char a)
{
mSize = n;
mCapacity = n + 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
mpData[i] = a;
mpData[mSize] = '\0';
}
String::~String()
{
std::free(mpData);
}
void String::reserve(std::size_t capacity)
{
if (capacity <= mCapacity)
return;
mCapacity = capacity;
char* newData = (char*)std::malloc(sizeof(char) * mCapacity);
for (std::size_t i = 0; i < mSize; ++i)
newData[i] = mpData[i];
newData[mSize] = '\0';
std::free(mpData);
mpData = newData;
}
void String::resize(std::size_t size)
{
reserve(size + 1);
mSize = size;
mpData[mSize] = '\0';
}
String& String::operator=(const String& right)
{
if (this == &right)
return *this;
mSize = right.mSize;
resize(mSize);
for (std::size_t i = 0; i <= mSize; ++i)
mpData[i] = right.mpData[i];
return *this;
}
String String::operator+(const String& b)
{
String result;
result.resize(mSize + b.mSize);
for (std::size_t i = 0; i < mSize; ++i)
result.mpData[i] = mpData[i];
for (std::size_t i = 0; i < b.mSize; ++i)
result.mpData[mSize + i] = b.mpData[i];
result.mpData[result.mSize] = '\0';
return result;
}
String& String::operator+=(const String& right)
{
*this = *this + right;
return *this;
}
bool String::operator==(const String& right) const
{
if (mSize != right.mSize)
return false;
std::size_t i = 0;
while (i < mSize && mpData[i] == right.mpData[i])
i++;
return i == mSize;
}
bool String::operator<(const String& right) const
{
std::size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] < right.mpData[i];
}
bool String::operator<=(const String& right) const
{
std::size_t i = 0;
while (i < mSize && i < right.mSize && mpData[i] == right.mpData[i])
i++;
return mpData[i] <= right.mpData[i];
}
bool String::operator!=(const String& right) const
{
return !(*this == right);
}
bool String::operator>(const String& right) const
{
return !(*this <= right);
}
bool String::operator>=(const String& right) const
{
return !(*this < right);
}
char& String::operator[](std::size_t i)
{
return mpData[i];
}
char& String::at(std::size_t i)
{
if (i >= mSize)
{
std::cout << "Error! Index is out of bounds." << std::endl;
std::exit(1);
}
return mpData[i];
}
void String::clear()
{
std::free(mpData);
mSize = 0;
mCapacity = 1;
mpData = (char*)std::malloc(sizeof(char) * mCapacity);
mpData[0] = '\0';
}
void String::addCharacter(char c)
{
if (mSize + 1 == mCapacity)
reserve(2 * mCapacity);
mpData[mSize] = c;
resize(mSize + 1);
}
std::size_t String::getSize() const {return mSize;}
std::size_t String::getCapacity() const {return mCapacity;}
const char* String::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;
}
}

View file

@ -0,0 +1,54 @@
#pragma once
#include <iostream>
#include <cstdlib>
namespace mipt {
class String
{
private:
std::size_t mSize;
std::size_t mCapacity;
char* mpData;
public:
String(const char* str);
String();
String(const String& s);
String(std::size_t n, char a);
~String();
void reserve(std::size_t capacity);
void resize(std::size_t size);
String& operator=(const String& right);
String operator+(const String& b);
String& operator+=(const String& right);
bool operator==(const String& right) const;
bool operator<(const String& right) const;
bool operator<=(const String& right) const;
bool operator!=(const String& right) const;
bool operator>(const String& right) const;
bool operator>=(const String& right) const;
char& operator[](std::size_t i);
char& at(std::size_t i);
void clear();
void addCharacter(char c);
std::size_t getSize() const;
std::size_t getCapacity() const;
const char* cStr() const;
};
std::ostream& operator<<(std::ostream& out, const String& s);
std::istream& operator>>(std::istream& in, String& s);
}