diff --git a/01_week/tasks/addition/addition.cpp b/01_week/tasks/addition/addition.cpp index 92872802..f11ce78a 100644 --- a/01_week/tasks/addition/addition.cpp +++ b/01_week/tasks/addition/addition.cpp @@ -3,5 +3,8 @@ int64_t Addition(int a, int b) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + int64_t a_64 = static_cast(a); + int64_t b_64 = static_cast(b); + int64_t sum = a_64 + b_64; + return sum; +} diff --git a/01_week/tasks/char_changer/char_changer.cpp b/01_week/tasks/char_changer/char_changer.cpp index 3a7344d9..8cf97e17 100644 --- a/01_week/tasks/char_changer/char_changer.cpp +++ b/01_week/tasks/char_changer/char_changer.cpp @@ -1,7 +1,50 @@ #include #include - +#include size_t CharChanger(char array[], size_t size, char delimiter = ' ') { - throw std::runtime_error{"Not implemented"}; + size_t position = 0; + char current; + char next; + unsigned int n_repited_char = 1; + bool is_char_repited = false; + for (size_t i = 0; i < size-1; ++i) { + current = array[i]; + next = array[i+1]; + if (next == current) { // замена повторяющихся символов + ++n_repited_char; + is_char_repited = true; + continue; + } + if (ispunct(current)) { //проверка на другие символы + array[position] = '_'; + } + if (isdigit(current)) { // проверка на цифру + array[position] = '*'; + } + if (islower(current)) { //проверка на пропись + array[position] = current - 32; + } + if (isupper(current)) { //проверка на пропись + array[position] = current; + } + if (isspace(current)) { //проверка единичного символа на пробел + array[position] = delimiter; + } + + if (is_char_repited) { // учет повторений + if (isspace(current)) { // при пробеле + array[position] = delimiter; + } + else { // при символе + ++position; + array[position] = (n_repited_char < 10) ? ('0' + n_repited_char) : '0'; + } + is_char_repited = false; + n_repited_char = 1; + } + ++position; + } + array[position] = '\0'; + return position; } diff --git a/01_week/tasks/check_flags/check_flags.cpp b/01_week/tasks/check_flags/check_flags.cpp index 75e7c652..c6a31a12 100644 --- a/01_week/tasks/check_flags/check_flags.cpp +++ b/01_week/tasks/check_flags/check_flags.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include enum class CheckFlags : uint8_t { @@ -14,5 +16,49 @@ enum class CheckFlags : uint8_t { }; void PrintCheckFlags(CheckFlags flags) { - throw std::runtime_error{"Not implemented"}; + + uint8_t value = static_cast(flags); + if (value > static_cast(CheckFlags::ALL)){ + return; // Если выходит за диапазон то вывод пустой + } + if (value == static_cast(CheckFlags::NONE)){ + std::cout << "[]"; + return; // Если 0 то пустые кавычки + } + + std::string check_flags = "["; + bool first = true; + + if ((value & static_cast(CheckFlags::TIME)) != 0){ + if (!first) check_flags += ","; + check_flags += "TIME"; + first = false; + } + if ((value & static_cast(CheckFlags::DATE)) != 0){ + if (!first) check_flags += ","; + check_flags += "DATE"; + first = false; + } + if ((value & static_cast(CheckFlags::USER)) != 0){ + if (!first) check_flags += ","; + check_flags += "USER"; + first = false; + } + if ((value & static_cast(CheckFlags::CERT)) != 0){ + if (!first) check_flags += ","; + check_flags += "CERT"; + first = false; + } + if ((value & static_cast(CheckFlags::KEYS)) != 0){ + if (!first) check_flags += ","; + check_flags += "KEYS"; + first = false; + } + if ((value & static_cast(CheckFlags::DEST)) != 0){ + if (!first) check_flags += ","; + check_flags += "DEST"; + first = false; + } + check_flags += "]"; + std::cout << check_flags; } diff --git a/01_week/tasks/length_lit/length_lit.cpp b/01_week/tasks/length_lit/length_lit.cpp index e69de29b..7fac8ac7 100644 --- a/01_week/tasks/length_lit/length_lit.cpp +++ b/01_week/tasks/length_lit/length_lit.cpp @@ -0,0 +1,41 @@ +// ft -> в другие единицы +constexpr long double operator""_ft_to_in(long double ft) { + return ft*12.0; +} +constexpr long double operator""_ft_to_m(long double ft) { + return ft*0.3048; +} +constexpr long double operator""_ft_to_cm(long double ft) { + return ft*30.48; +} +// m-> в другие единицы +constexpr long double operator""_m_to_ft(long double m) { + return m/0.3048; +} +constexpr long double operator""_m_to_in(long double m) { + return m/0.0254; +} +constexpr long double operator""_m_to_cm(long double m) { + return m*100.0; +} +// in-> в другие единицы +constexpr long double operator""_in_to_ft(long double in) { + return in/12.0; +} +constexpr long double operator""_in_to_m(long double in) { + return in*0.0254; +} +constexpr long double operator""_in_to_cm(long double in) { + return in*2.54; +} +// cm-> в другие единицы + +constexpr long double operator""_cm_to_ft(long double cm) { + return cm/30.48; +} +constexpr long double operator""_cm_to_in(long double cm) { + return cm/2.54; +} +constexpr long double operator""_cm_to_m(long double cm) { + return cm/100.0; +} diff --git a/01_week/tasks/print_bits/print_bits.cpp b/01_week/tasks/print_bits/print_bits.cpp index a48a43c1..1ee478c2 100644 --- a/01_week/tasks/print_bits/print_bits.cpp +++ b/01_week/tasks/print_bits/print_bits.cpp @@ -1,7 +1,29 @@ #include #include +#include void PrintBits(long long value, size_t bytes) { - throw std::runtime_error{"Not implemented"}; + if (bytes <= 0 || bytes > 8) { + return; + } + size_t size = (bytes * 8) + (bytes * 2 - 1) + 4; //размер массива под число включая (bytes * 8) цифр, (bytes * 2 - 1) символов ' после каждой 4 цифры, 3 символа: 0, b, \0 и \n + char bit_num[size]; + bit_num[0] = '0'; + bit_num[1] = 'b'; + bit_num[size - 1] = '\0'; + bit_num[size - 2] = '\n'; + for (size_t i = size - 3, comma_position = 1; i > 1; --i) { + if (comma_position % 5 == 0) { // добавление знака ' после каждых 4 цифр + bit_num[i] = '\''; + ++comma_position; + continue; + } + char symbol = '0' + (value & 1); + bit_num[i] = symbol; + value = value >> 1; + + ++comma_position; + } + std::cout << bit_num; } diff --git a/01_week/tasks/quadratic/quadratic.cpp b/01_week/tasks/quadratic/quadratic.cpp index abf7d632..1f477fb8 100644 --- a/01_week/tasks/quadratic/quadratic.cpp +++ b/01_week/tasks/quadratic/quadratic.cpp @@ -1,6 +1,38 @@ #include +#include +#include +#include void SolveQuadratic(int a, int b, int c) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + if (a == 0 && b != 0) { // проверяем уникальные случаи коэффициентов + double x1 = static_cast(-c)/b; + std::cout << std::setprecision(6) << x1; + return; + } + if (a == 0 && b == 0 && c != 0) { + std::cout << "no solutions"; + return; + } + if (a == 0 && b == 0 && c == 0) { + std::cout << "infinite solutions"; + return; + } +//Проверяем дискрименант + double D = b*b-4*a*c; + if (D > 0){ + double x1 = (-b - std::sqrt(D))/(2*a); + double x2 = (-b + std::sqrt(D))/(2*a); + std::cout << std::setprecision(6) << x1 << " " << x2; + return; + } + if (D == 0){ + double x1 = static_cast(-b)/(2*a); + std::cout << std::setprecision(6) << x1; + return; + } + if (D < 0){ + std::cout << "no solutions"; + return; + } +} diff --git a/01_week/tasks/rms/rms.cpp b/01_week/tasks/rms/rms.cpp index 6882f0a9..4ffcb3d9 100644 --- a/01_week/tasks/rms/rms.cpp +++ b/01_week/tasks/rms/rms.cpp @@ -1,7 +1,15 @@ -#include #include +#include double CalculateRMS(double values[], size_t size) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + if (!values || size == 0){ + return 0.0; + } + double sum_square = 0.0; + for (size_t i = 0; i < size; ++i){ + sum_square += std::pow(values[i], 2); + } + double RMS = std::sqrt(sum_square/size); + return RMS; +} diff --git a/02_week/tasks/func_array/func_array.cpp b/02_week/tasks/func_array/func_array.cpp index b327e68d..b88db657 100644 --- a/02_week/tasks/func_array/func_array.cpp +++ b/02_week/tasks/func_array/func_array.cpp @@ -1,6 +1,19 @@ #include +#include -double ApplyOperations(double a, double b /* other arguments */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +double ApplyOperations(double a, double b, double (*func[])(double, double), size_t size) { + if (size == 0){ + return 0.0; + } + + double result = 0; + for (size_t i = 0; i < size; ++i) { + if (func[i] == nullptr){ + result += 0.0; + continue; + } + result += func[i](a,b); + } + return result; +} diff --git a/02_week/tasks/last_of_us/last_of_us.cpp b/02_week/tasks/last_of_us/last_of_us.cpp index c7bf1a25..3847499d 100644 --- a/02_week/tasks/last_of_us/last_of_us.cpp +++ b/02_week/tasks/last_of_us/last_of_us.cpp @@ -1,6 +1,15 @@ #include +#include - -/* return_type */ FindLastElement(/* ptr_type */ begin, /* ptr_type */ end, /* func_type */ predicate) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +const int* FindLastElement(const int* begin, const int* end, bool (*predicate) (const int)) { + if ((end - begin) <= 0 || end == nullptr || begin == nullptr){ + return end; + } + const int* last = end; + for (; begin < end; ++begin){ + if (predicate(*begin)) { + last = begin; + } + } + return last; +} diff --git a/02_week/tasks/little_big/little_big.cpp b/02_week/tasks/little_big/little_big.cpp index abe24379..25308ae9 100644 --- a/02_week/tasks/little_big/little_big.cpp +++ b/02_week/tasks/little_big/little_big.cpp @@ -1,10 +1,44 @@ #include +#include +#include +#include -void PrintMemory(int /* write arguments here */) { - throw std::runtime_error{"Not implemented"}; +void PrintMemory(int number, bool invert = false) { + int* ptr_int = &number; + unsigned char* ptr_char = reinterpret_cast(ptr_int); + if (!invert) { + std::cout << "0x"; + for (unsigned int i = 0; i < sizeof(int); ++i) { + std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(ptr_char[i]); + } + std::cout << std::endl; + } + else { + std::cout << "0x"; + for (int i = sizeof(int) - 1; i >= 0; --i) { + std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(ptr_char[i]); + } + std::cout << std::endl; + } + } -void PrintMemory(double /* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +void PrintMemory(double number, bool invert = false) { + double* ptr_doub = &number; + unsigned char* ptr_char = reinterpret_cast(ptr_doub); + if (!invert) { + std::cout << "0x"; + for (unsigned int i = 0; i < sizeof(double); ++i) { + std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(ptr_char[i]); + } + std::cout << std::endl; + } + else { + std::cout << "0x"; + for (int i = sizeof(double) - 1; i >= 0; --i) { + std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0') << static_cast(ptr_char[i]); + } + std::cout << std::endl; + } +} diff --git a/02_week/tasks/longest/longest.cpp b/02_week/tasks/longest/longest.cpp index 04b3c354..25026327 100644 --- a/02_week/tasks/longest/longest.cpp +++ b/02_week/tasks/longest/longest.cpp @@ -1,6 +1,36 @@ #include +#include +char* FindLongestSubsequence(const char* begin, const char* end, size_t& count) { + if (begin == nullptr || end == nullptr || begin >= end) { + count = 0; + return nullptr; + } -/* return_type */ FindLongestSubsequence(/* ptr_type */ begin, /* ptr_type */ end, /* type */ count) { - throw std::runtime_error{"Not implemented"}; + const char* longest_start = begin; + const char* current_start = begin; + size_t max_length = 1; + size_t current_length = 1; + + for (const char* ptr = begin + 1; ptr < end; ++ptr) { + if (*ptr == *(ptr - 1)) { + ++current_length; + } else { + if (current_length > max_length) { + max_length = current_length; + longest_start = current_start; + } + current_start = ptr; + current_length = 1; + } + } + + // Если все символы повторяются нужно отдельно проверить еще раз + if (current_length > max_length) { + max_length = current_length; + longest_start = current_start; + } + + count = max_length; + return const_cast(longest_start); } diff --git a/02_week/tasks/pretty_array/pretty_array.cpp b/02_week/tasks/pretty_array/pretty_array.cpp index 48eab341..2264a11b 100644 --- a/02_week/tasks/pretty_array/pretty_array.cpp +++ b/02_week/tasks/pretty_array/pretty_array.cpp @@ -1,6 +1,43 @@ #include +#include +#include -void PrintArray(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +void PrintArray(const int* begin, const int* end, unsigned int limiter = 0) { + std::string numbers = "["; + int dist = end - begin; + unsigned int count = 0; + if (begin == nullptr || end == nullptr || (dist*dist) == 0){ // Проверка на nullptr или пустой массив + numbers+="]"; + std::cout << numbers << std::endl; + return; + } + + while (true){ + int num = *begin; + std::string reverse_number = ""; + while (num / 10 != 0) { // // Конвертация int в str и запись в массив numbers + reverse_number += '0' + (num % 10); + num /= 10; + } + reverse_number += '0' + num % 10; + + // Переворачиваем string number + std::string number; + for (int j = reverse_number.length() - 1; j >=0; --j) { + number += reverse_number[j]; + } + numbers += number; + if (dist*dist == 1) break; // ПРоверка последний ли это символ? + numbers += ", "; // Если не последний то добавляем ", " + ++count; // Если счетчик равен ограничителю, то добавляем "... " + if (limiter != 0 && count == limiter){ + numbers += "...\n "; + count = 0; + } + (dist > 0) ? ++begin : --begin; + dist = end - begin; + } + numbers += "]"; + std::cout << numbers << std::endl; +} diff --git a/02_week/tasks/swap_ptr/swap_ptr.cpp b/02_week/tasks/swap_ptr/swap_ptr.cpp index 93db625d..a6c88d7c 100644 --- a/02_week/tasks/swap_ptr/swap_ptr.cpp +++ b/02_week/tasks/swap_ptr/swap_ptr.cpp @@ -1,6 +1,8 @@ #include -void SwapPtr(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +void SwapPtr(auto*& ptr1, auto*& ptr2) { + auto* temp = ptr1; + ptr1 = ptr2; + ptr2 = temp; +} diff --git a/03_week/tasks/data_stats/data_stats.cpp b/03_week/tasks/data_stats/data_stats.cpp index b941c211..cc21efc5 100644 --- a/03_week/tasks/data_stats/data_stats.cpp +++ b/03_week/tasks/data_stats/data_stats.cpp @@ -1,11 +1,23 @@ #include - +#include struct DataStats { double avg = 0.0; double sd = 0.0; }; -/* return_type */ CalculateDataStats(/* args */) { - throw std::runtime_error{"Not implemented"}; +DataStats CalculateDataStats(const std::vector& data) { + DataStats p; + if (data.empty()) return p; + double sum_of_x = 0.0; + double sum_of_squares_x = 0.0; + size_t N = data.size(); + for (size_t i = 0; i < N; ++i){ + sum_of_x += data[i]; + sum_of_squares_x += static_cast(data[i])*data[i]; + } + p.avg = sum_of_x/N; + double variance = (sum_of_squares_x/N) - (sum_of_x/N)*(sum_of_x/N); + p.sd = sqrt(variance); + return p; } diff --git a/03_week/tasks/easy_compare/easy_compare.cpp b/03_week/tasks/easy_compare/easy_compare.cpp index dd5cb7f6..f32c9254 100644 --- a/03_week/tasks/easy_compare/easy_compare.cpp +++ b/03_week/tasks/easy_compare/easy_compare.cpp @@ -2,9 +2,9 @@ struct Date { - unsigned year; - unsigned month; - unsigned day; + unsigned year = 0; + unsigned month = 0; + unsigned day = 0; }; struct StudentInfo { @@ -13,4 +13,34 @@ struct StudentInfo { int score; unsigned course; Date birth_date; -}; \ No newline at end of file +}; + +bool operator==(const Date& date1, const Date& date2) { + return std::tie(date1.year, date1.month, date1.day) == std::tie(date2.year, date2.month, date2.day); +} +bool operator<(const Date& date1, const Date& date2) { + return std::tie(date1.year, date1.month, date1.day) < std::tie(date2.year, date2.month, date2.day); +} +bool operator!=(const Date& date1, const Date& date2) { + return !(date1 == date2); +} +bool operator>(const Date& date1, const Date& date2) { + return !(date1 < date2 || date1 == date2); +} +bool operator>=(const Date& date1, const Date& date2) { + return !(date1 < date2); +} +bool operator<=(const Date& date1, const Date& date2) { + return (date1 < date2 || date1 == date2); +} + +bool operator==(const StudentInfo& student1, const StudentInfo& student2) { + return std::tie(student1.mark, student1.score) == std::tie(student2.mark, student2.score); +} +bool operator<(const StudentInfo& student1, const StudentInfo& student2) { + if (student1.mark != student2.mark) return student1.mark > student2.mark; + if (student1.score != student2.score) return student1.score < student2.score; + if (student1.course != student2.course) return student1.course > student2.course; + if (student1.birth_date != student2.birth_date) return student1.birth_date < student2.birth_date; + return false; +} diff --git a/03_week/tasks/enum_operators/enum_operators.cpp b/03_week/tasks/enum_operators/enum_operators.cpp index a539be38..a878a1da 100644 --- a/03_week/tasks/enum_operators/enum_operators.cpp +++ b/03_week/tasks/enum_operators/enum_operators.cpp @@ -1,5 +1,6 @@ #include #include +#include enum class CheckFlags : uint8_t { NONE = 0, @@ -12,22 +13,77 @@ enum class CheckFlags : uint8_t { ALL = TIME | DATE | USER | CERT | KEYS | DEST }; -/* return_type */ operator|(/* args */) { - throw std::runtime_error{"Not implemented"}; +CheckFlags operator|(CheckFlags flags1, CheckFlags flags2) { + uint8_t all = static_cast(CheckFlags::ALL); + uint8_t value1 = static_cast(flags1) & all; // Обрезаем все биты слева которые заходят за допустимый размер all + uint8_t value2 = static_cast(flags2) & all; + return static_cast(value1 | value2); } -/* return_type */ operator&(/* args */) { - throw std::runtime_error{"Not implemented"}; +CheckFlags operator^(CheckFlags flags1, CheckFlags flags2) { + uint8_t all = static_cast(CheckFlags::ALL); + uint8_t value1 = static_cast(flags1) & all; + uint8_t value2 = static_cast(flags2) & all; + return static_cast(value1 ^ value2); // побитовый xor для двух чисел и последующий каст } -/* return_type */ operator^(/* args */) { - throw std::runtime_error{"Not implemented"}; + +bool operator&(CheckFlags flags1, CheckFlags flags2) { + uint8_t all = static_cast(CheckFlags::ALL); + uint8_t value1 = static_cast(flags1) & all; + uint8_t value2 = static_cast(flags2) & all; + if (value1 == static_cast(CheckFlags::NONE) || value2 == static_cast(CheckFlags::NONE)) return false; + return ((value1 & value2) == value1) || ((value1 & value2) == value2); // проверка является один из операндов подмножеством другого + } -/* return_type */ operator~(/* args */) { - throw std::runtime_error{"Not implemented"}; +CheckFlags operator~(CheckFlags flags) { + uint8_t all = static_cast(CheckFlags::ALL); + uint8_t value = static_cast(flags); + value = (value == static_cast(CheckFlags::NONE)) ? static_cast(CheckFlags::ALL) : ~value; // если NONE то перевод в ALL если нет то инвертируем + return static_cast(value & all); // Обрезаем все биты слева которые заходят за допустимый размер all } -/* return_type */ operator<<(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::ostream& operator<<(std::ostream& os, const CheckFlags& flags) { + uint8_t all = static_cast(CheckFlags::ALL); + uint8_t value = static_cast(flags) & all; // Обрезаем все биты слева которые заходят за допустимый размер all + + if (value == static_cast(CheckFlags::NONE)){ + os << "NONE"; + return os; + } + + bool first = true; // Если вывод флага первый, то перед ним запятая не ставится +// ПРоверка наличия каждого флага в flags + if ((value & static_cast(CheckFlags::TIME)) != 0){ + if (!first) os << ", "; // Если вывод не первый, то перед ним ставится запятая + os << "TIME"; + first = false; + } + if ((value & static_cast(CheckFlags::DATE)) != 0){ + if (!first) os << ", "; + os << "DATE"; + first = false; + } + if ((value & static_cast(CheckFlags::USER)) != 0){ + if (!first) os << ", "; + os << "USER"; + first = false; + } + if ((value & static_cast(CheckFlags::CERT)) != 0){ + if (!first) os << ", "; + os << "CERT"; + first = false; + } + if ((value & static_cast(CheckFlags::KEYS)) != 0){ + if (!first) os << ", "; + os << "KEYS"; + first = false; + } + if ((value & static_cast(CheckFlags::DEST)) != 0){ + if (!first) os << ", "; + os << "DEST"; + first = false; + } + return os; } diff --git a/03_week/tasks/filter/filter.cpp b/03_week/tasks/filter/filter.cpp index 6648cb39..10f34673 100644 --- a/03_week/tasks/filter/filter.cpp +++ b/03_week/tasks/filter/filter.cpp @@ -1,6 +1,15 @@ #include +#include -/* return_type */ Filter(/* args */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +void Filter(std::vector& vec, bool (*pred_func) (int)) { + if (!pred_func) return; + size_t write_index = 0; + for (size_t i = 0; i < vec.size(); ++i) { + if (pred_func(vec[i])) { + vec[write_index] = vec[i]; + ++write_index; + } + } + vec.resize(write_index); +} diff --git a/03_week/tasks/find_all/find_all.cpp b/03_week/tasks/find_all/find_all.cpp index 74f393b2..0f4edaa5 100644 --- a/03_week/tasks/find_all/find_all.cpp +++ b/03_week/tasks/find_all/find_all.cpp @@ -1,6 +1,17 @@ #include +#include -/* return_type */ FindAll(/* args */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +std::vector FindAll(const std::vector& vec, bool (*pred_func) (int)) { + std::vector result; + if (!pred_func || vec.empty()) + return result; + result.reserve(vec.size()); + for (size_t i = 0; i < vec.size(); ++i){ + if (pred_func(vec[i])){ + result.push_back(i); + } + } + result.shrink_to_fit(); + return result; +} diff --git a/03_week/tasks/minmax/minmax.cpp b/03_week/tasks/minmax/minmax.cpp index c2869799..3ebd8ab0 100644 --- a/03_week/tasks/minmax/minmax.cpp +++ b/03_week/tasks/minmax/minmax.cpp @@ -1,6 +1,23 @@ #include +#include - -/* return_type */ MinMax(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::pair ::const_iterator, std::vector::const_iterator> MinMax(const std::vector & vec) { + if (vec.empty()) { + return {vec.end(), vec.end()}; + } + int min = vec[0]; + int max = vec[0]; + auto min_it = vec.begin(); + auto max_it = vec.begin(); + for (auto it = vec.begin(); it!= vec.end(); ++it){ + if (*it < min){ + min = *it; + min_it = it; + } + if (*it >= max){ + max = *it; + max_it = it; + } + } + return {min_it, max_it}; } diff --git a/03_week/tasks/os_overload/os_overload.cpp b/03_week/tasks/os_overload/os_overload.cpp index e473418d..8573b3d5 100644 --- a/03_week/tasks/os_overload/os_overload.cpp +++ b/03_week/tasks/os_overload/os_overload.cpp @@ -1,21 +1,51 @@ #include #include #include - +#include struct Coord2D { - int x; - int y; + int x = 0; + int y = 0; }; struct Circle { Coord2D coord; - unsigned radius; + unsigned radius = 1; }; using CircleRegion = std::pair; using CircleRegionList = std::vector; -/* return_type */ operator<<(/* args */) { - throw std::runtime_error{"Not implemented"}; + +std::ostream& operator<<(std::ostream& os, const Coord2D& coord2D) { + os << "("<< coord2D.x << ", " << coord2D.y << ")"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const Circle& circle) { + if (circle.radius == 0) { + os << "circle[]"; + return os; + } + os << "circle["<< circle.coord << ", r = " << circle.radius << "]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const CircleRegion& circleRegion) { + os << (circleRegion.second ? "+" : "-"); + os << circleRegion.first; + return os; +} + +std::ostream& operator<<(std::ostream& os, const CircleRegionList& circleRegionList) { + if (circleRegionList.empty()) { + os << "{}"; + return os; + } + os << "{" << "\n"; + for (size_t i = 0; i < circleRegionList.size() - 1; ++i) { + os << "\t" << circleRegionList[i] << "," << "\n"; + } + os << "\t" << circleRegionList[circleRegionList.size() - 1] << "\n" << "}"; + return os; } diff --git a/03_week/tasks/range/range.cpp b/03_week/tasks/range/range.cpp index d2085495..f7a11122 100644 --- a/03_week/tasks/range/range.cpp +++ b/03_week/tasks/range/range.cpp @@ -2,6 +2,14 @@ #include -std::vector Range(int from, int to, int step) { - throw std::runtime_error{"Not implemented"}; +std::vector Range(int from, int to, int step = 1) { + std::vector result; + if ((to - from)*step <= 0) return result; // проверка на невалидные параметры + size_t size = (step > 0) ? ((to - from - 1)/step + 1) : ((from - to - 1)/(-step) + 1); // определим кол-во элементов которое необходимо выделить для вектора + + result.reserve(size); // выделяем память под кол-во элементов size + for (size_t i = 0; i < size; ++i){ + result.push_back(from + i * step); + } + return result; } diff --git a/03_week/tasks/unique/unique.cpp b/03_week/tasks/unique/unique.cpp index 9d2545bb..0f1fd2aa 100644 --- a/03_week/tasks/unique/unique.cpp +++ b/03_week/tasks/unique/unique.cpp @@ -1,6 +1,19 @@ #include #include -/* return_type */ Unique(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::vector Unique(const std::vector& vec) { + std::vector result; + if (vec.empty()) return result; + result.reserve(vec.size()); // выделяем кол-во памяти неменьше чем для vec + result.push_back(vec[0]); // заполняем первым элементом + size_t write_index = 0; // блуждающий индекс для вектора result + for (size_t i = 1; i < vec.size(); ++i) { + if (result[write_index] != vec[i]){ // если следующий элемент не равен предыдущему то добавляем его в result + result.push_back(vec[i]); + ++write_index; + } + } + ++write_index; // Костыль чтобы учесть первый добавленный элемент + result.shrink_to_fit(); // обрезаем лишнюю память + return result; } diff --git a/04_week/04_class.md b/04_week/04_class.md deleted file mode 100644 index 46e00076..00000000 --- a/04_week/04_class.md +++ /dev/null @@ -1,902 +0,0 @@ -# Лекция 4. ООП. Класс - -1. [ООП](#oop) - - [Инкапсуляция](#encapsulation) - - [Наследование](#inheritance) - - [Полиморфизм](#polymorphism) - - [Абстракция](#abstraction) -1. [Класс](#class) - - [Спецификаторы доступа](#access_specifiers) - - [Отличие класса и структуры](#class_struct_diff) - - [Пустой класс](#class_empty) - - [Поля класса](#class_fields) - - [Инициализация полей значением по умолчанию](#field_default_init) - - [Конструктор](#ctor) - - [Список инициализации полей класса](#member_initializer_list) - - [Параметризованный конструктор](#parameterized_ctor) - - [Конструктор по умолчанию](#default_ctor) - - [Конструктор копирования](#copy_ctor) - - [Указатель на себя `this`](#this_ptr) - - [Копирующий оператор присваивания](#copy_assignment) - - [Деструктор](#dtor) - - [Конструктор преобразования](#converting_ctor) - - [Ключевое слово `explicit`](#explicit) - - [Конструктор от `std::initializer_list`(_C++11_)](#ctor_std_initializer_list) - - [Делегирующий конструктор (_C++11_)](#delegating_ctor) - - [Ключевое слово `default` (_С++11_)](#keyword_default) - - [Ключевое слово `delete` (_С++11_)](#keyword_delete) - - [Методы](#methods) - - [Определение методов вне класса](#methods_definition_outside) - - [CV-квалификация методов ](#cv_for_methods) - - [Оператор преобразования](#conversion_operator) - - [Перегрузка операторов внутри класса](#class_operator_overloading_inside) - - [Перегрузка операторов вне класса](#class_operator_overloading_outside) - - [Ключевое слово `friend`](#keyword_friend) - - [Ключевое слово `mutable`](#keyword_mutable) - - -## ООП - -Объектно-ориентированное программирование - парадигма программирования, которая -основывается на представление в коде программы различных объектов, взаимодействующих -друг с другом. - -Класс - пользовательский тип данных, шаблон (макет) для создания объектов и описания -их характеристик, функций. - -Объект - экземпляр класса. Объект включает данные (поля) и методы (функции). -Что позволяет хранить характеристики объекта, изменять их и взаимодействовать с -другими объектами. - -Основные принципы ООП: - -- Инкапсуляция -- Наследование -- Полиморфизм -- Абстракция - -### Инкапсуляция - -Инкапсуляция - объединение данных и методов для работы с данными внутри класса. -Сокрытие деталей реализации класса. - -```c++ -class Budget { -public: - void increase_balance(double value) { - budget_ += value; - } -private: - double budget_; -}; -``` - -### Наследование - -Наследование - механизм создания новых классов на основе существующих. Позволяет -строить иерархию классов и переиспользовать код классов родителей внутри -классов наследников. - -```c++ -class Animal { /* common data */}; -class Cat : public Animal {}; -class Dog : public Animal {}; -``` - -### Полиморфизм - -Полиморфизм - возможность различного поведения сущностей C++. - -Виды полиморфизма: - -- статический (на этапе компиляции, шаблоны, перегрузка функций) -- динамический (во время выполнения программы, виртуальные методы) - -```c++ -class Shape { -public: - virtual void draw() = 0; -}; -class Circle : public Shape { - void draw() override { /* рисуем круг */ } -}; -``` - -### Абстракция - -Абстракция - упрощение сложных вещей через выделение основных характеристик. - -## Класс - -Класс - пользовательский тип данных, который объединяет в себе данные (поля класса) -и функции для работы с данными (методы класса), представляет собой макет для -создания объектов (экземпляров) данного типа. - -Синтаксис: `class {};` - -- `` - имя класса, пользовательского типа данных -- `` - тело класса, включающее поля, методы, конструкторы и деструктор - -### Спецификаторы доступа - -Для ограничения видимости полей и методов внутри класса используются -спецификаторы доступа, весь код после спецификатора имеет соответствующий тип -доступа: - -- `public` - публичный доступ, поле или метод класса доступны извне -- `protected` - защищенный доступ, поля и методы доступны наследникам класса - и внутри класса -- `private` - приватный доступ, поля и методы доступны только внутри класса. - -Синтаксис внутри класса или структуры: `:` - -Указывать спецификаторы доступа можно произвольное число раз. - -```c++ -class User { -public: - /* some data and functions for everyone */ -protected: - /* some data and functions for children classes */ -private: - /* some data and functions inside class */ -}; -``` - -Приватные поля и методы будут недоступны снаружи, то есть **НЕЛЬЗЯ** к ним -обратится или вызвать через экземляр класс, используя операторы `.`, `->`. - -Всё содержимое класса по умолчанию имеет спецификатор доступа `private`, -несмотря на это часто принято явно указывать данный спецификатор, даже при -определении полей класса в самом начале тела класса. - -### Отличие класса и структуры - -Структура `struct` и класс `class` имеют одинаковые возможности в C++. - -Отличие заключается, что содержимое структуры по умолчанию имеет публичный -доступ `public`, а содержимое класса приватный `private` - -Структура нужна для взаимодействия с `legacy` кодом на языке C, а также для -публичных классов. - -Несмотря на одинаковые возможности, принято разделять структуру и класс -семантически. Так, структуру используют только с публичными полями, а класс -с приватными. Создавать классы и структуры со смешанным типом полей не -рекомендуется, так как это может быть не очевидно и не понятно программистам, -читающим код. - -### Пустой класс - -Пустой класс имеет размер 1 байт, поскольку объект такого класса можно создать -и необходимо иметь адресс данного объекта, чтобы иметь адресс, необходимо что-то -положить в память по определенному адресу. - -Чаще используется пустая структура. Такая структура может понадобитсья в качестве -именнованного тега. Пока будем просто считать, что иногда надо. - -### Поля класса - -Поля класса представляют собой внутренние переменные произвольного типа. -К полям класса внутри класса можно обращаться по имени. В качестве поля можно -использовать указатели и ссылки. - -В случае ссылок необходимо их инициализировоать при создании объекта. Например, -можно проинициализирвоать адресом объекта из глобальной области видимости. А еще -это можно сделать в списке инициализации при конструировании объекта. - -Существуют разные стили кода к именованию полей класса. Часто встречается: - -- `m_` - добавляют `m_` в качестве префикса к перименной (`m` - `member`) -- `_` - добавляют `_` в качестве постфикса к переменной. - -```c++ -// inside class -int m_value; -int value_; -``` - -Поля класса хранятся в классе и инициализируются в порядке их объявления. - -Поля уникальны для каждого экземпляра класса. - -### Инициализация полей значением по умолчанию - -Аналогично структурам рекомендуется всегда инициализировать поля внутри класса. - -```c++ -class Time { -private: - int hour_ = 0; - int minute_{0}; // uniform -}; -``` - -Иначе в полях класса также может лежать мусор. - -### Конструктор - -Конструктор это особый метод класса, который используется для конструирования -объекта. - -Синтаксис: `() {}` - -- `` - имя конструктора должно совпадать с именем класса -- `` - аргументы конструктора. -- `` - тело конструктора. - -В зависимости от аргументов конструктора выделяют различные типы конструктора. -Основные способы конструирования объекта: - -- Параметризованный конструктор -- Конструктор по умолчанию -- Конструктор копирования -- Копирующий оператор присваивания -- Конструктор перемещения -- Перемещающий оператор присваивания - -Важно понимать, что если конструкторы не определены, то компилятор самостоятельно -сгенерирует конструкторы. Но если определен, хотя бы один конструктор, то -компилятор скорее всего этого не сделает. - -Важно понимать, что при входе в тело конструктора все поля уже проинициализированы -и в теле может происходить только присваивание новых значений полям класса. -Следовательно, в теле уже нельзя изменить константное поле или инициализировать -ссылку. - -Проинициализировать константу и ссылку можно не только значением по -умолчанию или значением (адресом) переменной из глобальной области видимости. -Для этого в синтаксисе конструктора предусмотрен список инициализации. - -### Список инициализации полей класса - -Список инициализации полей (_member initializer list_) позволяет инициализировать -поля в момент создания объекта. В списке инициализации доступны аргументы -конструктора и имена полей класса. Список инициализации указывается между сигнатурой -и телом конструктора, и выглядит как перечисление после символа `:` через запятую -полей класса и внутри `()` или `{}` их инициализирующих значений. - -Синтаксис: `() : {}` - -- `` - список инициализации = `(), {}` - -```c++ -class InitList { -public: - InitList(int val) : a_(val), b_(val), c_(val) {} -public: - int a_; int b_; int c_; -}; -``` - -Причем имена полей класса и имена параметров могут полностью совпадать, конфликта -имен не будет, поскольку компилятор понимает, что нужно инициализировать поля. - -```c++ -class InitSameName { -public: - InitSameName(int a, int b, int c) : a(a), b(b), c(c) {} -public: - int a; int b; int c; -}; -``` - -Также, следует отметить, что в качестве инициализирующего значения, может использоваться -не только переменная или константа, но также выражение (_expression_) и результат -вызова функции. - -**ВАЖНО**, что инициализация происходит в порядке полей класса, и не зависит от -порядка в списке инициализации. Поэтому важно самостоятельно отслеживать -правильный порядок инициализации. - -```c++ -class BadOrderInit { -public: - BadOrderInit(int val) : c(val), b(c + 1), a(10) {} -public: - int a; int b; int c; -}; -``` -- `c` используется неинициализированной при инициализации `b` (**UB**) - -Если поля класса объявлены со значением по умолчанию, то они будут проигнорированы -для полей в списке инициализации. - -```c++ -class BadOrderInit { -public: - BadOrderInit(int val) : c(val), b(c + 1), a(10) {} -public: - int a = 7; int b = 7; int c = 7; -}; -``` -- значение `7` будет проигнорированно, по-прежнему **UB** - -Списки инициализации могут быть неполными. Тогда недостающие поля будут -сконструированы со значениями по умолчанию, а при их отсутствии инициализируются -мусором. - -```c++ -class BadOrderInitNoAB { -public: - BadOrderInitNoAB(int val) : c(val) {} -public: - int a; int b = 7; int c = 7; -}; -``` -- в поле `b` будет значение `7`, в `a` будет мусор - -Список инициализации позволяет сконструировать константное поле и поле ссылку извне: - -```c++ -class RefConst { -public: - RefConst(int value, int& ref, const double& cref) - : id_(value), ref_(ref), const_ref_(cref) {} -private: - const int id_; - int& ref_; - const double& const_ref_; -}; -``` - -### Параметризованный конструктор - -Конструктор, который имеет параметры (аргументы) называют параметризованным -конструктором (конструктором с параметрами). Аргументов может быть несколько -и они могут иметь значения по умолчанию, Таким образом, конструктор может -быть перегружен. - -```c++ -class Time { -public: - Time(int hour, int minute, int second) - : hour_(hour), minute_(minute), second_(second) {} -private: - int hour_, minute_, second_; -}; -``` - -Если конструктор имеет у всех аргументов значение по умолчанию, то такой -конструктор перегружает конструктор по умолчанию. - -```c++ -class Time { -public: - Time(int hour = 0, int minute = 0, int second = 0) - : hour_(hour), minute_(minute), second_(second) {} -private: - int hour_, minute_, second_; -}; -``` - -Для создания объекта класса необходим вызов конструктора. Синтаксис вызова констуктора: - -```c++ -Time t1(1, 1, 1); -Time t2{1, 1, 1}; -Time t3 = {1, 1, 1} -Time t4 = Time{1, 1, 1}; -Time t5 = Time(1, 1, 1); -``` - -Аналогично для всех его вариантов перегрузки. - -### Конструктор по умолчанию - -Конструктор по умолчанию представляет собой конструктор без аргументов. -Часто для простых класов конструктор имеет пустое тело. Удобно использовать -значение по умолчанию для инициализации. - -Синтаксис: `() {}` - -Часто имеет пустое тело для тривиальных случаев. - -Если не определен ни один конструктор, то компилятор самостоятельно сгенерирует -данный конструктор. - -```c++ -class DefaultCtor { -public: - DefaultCtor() {} -private: - int value = 0; -}; -``` - -Вызов конструктора: - -```c++ -DefaultCtor obj; -DefaultCtor obj2{}; -DefaultCtor obj3 = {}; -DefaultCtor obj4 = DefaultCtor{}; -DefaultCtor obj5 = DefaultCtor(); -``` -- во всех этих случаях вызовется только конструктор по умолчанию один раз - -### Конструктор копирования - -Конструктор копирования необходим для создания копии объекта из объекта того -же типа. Представляет собой конструктор, принимающий в качестве аргументов -константную ссылку того же типа, что и сам класс. - -Синтаксис: `(const & ) {}` - -```c++ -class Time { -public: - Time(const Time& other) - : hour_(other.hour_), minute_(other.minute_), second_(other.second_) {} -private: - int hour_, minute_, second_; -}; -``` - -Поля другого объекта того же класса доступны внутри методов класса даже если они -приватные. - -Вызывается конструктор копирования: - -- при передаче в функцию по значению -- при возврате объекта соответствующего значения по значению -- при конструировании одного объекта из другого - -```c++ -Time t; -Time t1 = t; // copy ctor -Time t2(t); // copy ctor -Time t3{t}; // copy ctor -``` - -### Указатель на себя `this` - -Внутри класса, в методах, в том числе конструкторах, можно получить указатель на -себя (объект класса, который вызывает данный метод) с помощью ключевого слова `this`. - -Можно использовать `this`, как в качестве значения по умолчанию, так и в списке -инициализации. - -```c++ -class Self { -public: - Self() : self(this) {}; - Self* GetPtr() { return self; } - Self& GetRef() { return *this; } -private: - Self* self = this; -}; -``` - -Можно считать что указатель на себя передается первым неявным аргументом в конструкторы, -методы и операторы класса. - -Через указатель можно явно обращаться к полям класса, но как правило, так не делают - -```c++ -// inside methods -this->self; -``` - -### Копирующий оператор присваивания - -Оператор присвания необходим при присваивании одного созданного объекта другому. -Если один из объектов не создан, то он не будет вызываться, а будет вызываться -конструктор копирования, даже если в инструкции есть `=`. - -Как правило, оператор возвращает ссылку на себя (экземпляр текущего класса), что -позволяет испоьзовать цепочку из операторов `=`. Для этого необходимо вернуть из -оператора разыменованный указатель на себя `return *this;`. - -Синтаксис: `& operator=(const & ) {}` - -Поскольку язык не запрещает присвоить объект самому себе, как правило, в копирующем -операторе присваивания выполняют проверку на самоприсваивание. Особенно это -критично для классов владеющих ресурсами (выделяющих память), что может привести -к **UB** - -```c++ -class Time { -public: - Time& operator=(const Time& other) { - if (this == &other) { - return *this; - } - hour_ = other.hour_; - minute_ = other.minute_; - second_ = other.second_; - return *this; - } -private: - int hour_, minute_, second_; -}; -``` - -Вызов оператора: - -```c++ -Time t1, t2, t3; -t1 = t2; // copy assignment -t1 = t1; // copy assignment -t1 = t2 = t3; // copy assignment -auto t4 = t1; // copy ctor (not a copy assignment!) -``` - -### Деструктор - -Особый метод, вызываемый перед разрушением объекта, когда заканчивается время -жизни объекта. - -Синтаксис: `~() {}` - -Если в конструкторе выполнялось ручное выделение ресурсов, то в деструкторе -необходимо обязательно освободить ресурсы. Иначе деструктор остается тривиальным -и генерируется компилятором по умолчанию. - -Деструкторы вызываются в обратном порядке по отношению к конструируемым объектам -при выходе из области видимости. Последний сконструированный объект, будет разрушен -первым. - -### Конструктор преобразования - -Конструктором преобразования называется конструктор, принимающий один аргумент -другого произвольного типа. Данный конструктор разрешает неявное преобразование -из указанного типа в тип класса. - -```c++ -class Integer { -private: - int value; -public: - Integer(int v) : value(v) {} - Integer(char c) : value(static_cast(c)) {} -}; -``` - -Таким образом, если функция принимает пользовательский класс, а класс имеет -конструктор преобразования от другого типа, то в функцию можно передать -непосредственно этот другой тип, произойдет неявное преобразование с помощью -соответствующего конструктора: - -```c++ -int DoSomething(Integer i) {} - -int main() { - Integer i{3}; - int value = 5; - char c = 'I'; - DoSomething(i); // OK - DoSomething(value); // OK - DoSomething(5); // OK - DoSomething(c); // OK - DoSomething('i'); // OK -} -``` - -**ВАЖНО** понимать, что при наличии конструктора присваивания из другого типа, -компилятор **НЕ** будет генеировать оператор присваивания из данного типа, его -необходимо определять самостоятельно. - -### Ключевое слово `explicit` - -Ключевое слово `explicit` используется как спецификатор перед именем конструктора -и позволяет запретить неявное преобразование и сообщает компилятору, что данный -конструктор можно вызывать только явно. - -```c++ -class Integer { -private: - int value; -public: - Integer(int v) : value(v) {} - Integer(char c) : value(static_cast(c)) {} - explicit Integer(double d) : value(static_cast(d)) {} -}; -``` - -Неявно такой конструктор вызвать нельзя: - -```c++ -//Integer i2 = 3.14; // compile error -Integer i3 = Integer{3.14}; // OK - -int DoSomething(Integer i) {} - -int main() { - double d = 3.14; - //DoSomething(d); // compile error - //DoSomething(3.14); // compile error - DoSomething(Integer{3.14}); // OK - DoSomething(Integer(3.14)); // OK -} -``` - -Также спецификатор `explicit` можно использовать с оператором преобразования, об этом -после знакомства с методами. - -### Конструктор от `std::initializer_list`(_C++11_) - -В C++11 появился контейнер список инициализации `std::initializer_list`, который -позволяет инициализировать класс набором элементов. Что вызывает неоднозначность -при наличии параметризированных конструкторов какой конструктор вызывать. - -Конструктор по умолчанию имеет приоритет перед конструктором от списка инициализации. - -Список инициализации имеет приоритет перед параметризированными конструкторами при -использовании `{}`. - -```c++ -class Vector { -public: - Vector() {}; - Vector(size_t count); - Vector(int a, int b); - Vector(std::initializer_list list); -private: - std::vector data; -}; -``` - -Вызов конструкторов: - -```c++ -Vector v = {1, 2, 3, 4, 5}; // ctor std::initializer_list -Vector v2{1, 2, 3}; // ctor std::initializer_list -Vector v3(10); // ctor Vector(size_t) -Vector v4{10}; // ctor std::initializer_list -Vector v5 = {10}; // ctor std::initializer_list -Vector v6(10, 20); // ctor Vector(int a, int b) -Vector v7{10, 20}; // ctor std::initializer_list -Vector v8 = {10, 20}; // ctor std::initializer_list -Vector v9 = 10; // ctor Vector(size_t) implicit cast -Vector v10; // default ctor -Vector v11{}; // default ctor -Vector v12 = {}; // default ctor -``` - -### Делегирующий конструктор (_C++11_) - -Делегирующий конструктор - конструктор, который на месте списка инициализации -использует другой конструктор данного класса. В таком случае можно указать только -один целевой конструктор, дополнительно списки инициализации указать нельзя. - -```c++ -class Time { -public: - Time(int hour, int minute, int second) - : hour_(hour), minute_(minute), second_(second) {} - Time(int hour) : Time(hour, 0, 0) {} -private: - int hour_, minute_, second_; -}; -``` - -Делегирующий конструктор **НЕ** может быть рекурсивным. - -### Ключевое слово `default` (_С++11_) - -С помощью ключевого слова `default` можно явно попросить компилятор сгенерировать -конструктор (деструктор), указав после сигнатуры `= default`. Это более выразительно, -чем писать `{}` для конструктора по умолчанию. Рекомендуется к использованию. - -```c++ -class Value { -public: - Value(int x) : x_(x) {} - Value() = default; - Value(const Value& other) = default; - Value(Value&& other) = default; - Value& operator=(const Value& other) = default; - Value& operator=(Value&& other) = default; - ~Value() = default; -private: - int x = 0; -}; -``` - -### Ключевое слово `delete` (_С++11_) - -С помощью ключевого слова `delete` можно явно попросить компилятор удалить функцию -(запретить её использование), указав после сигнатуры `= delete`. Это более выразительно, -чем прятать конструкторы в приватную область класса. Рекомендуется к использованию. - -Можно использовать не только для конструкторов, деструкторов, но и для любых методов, -операторов, шаблонных функций, функций вне классов. - -```c++ -class Value { -public: - Value(int x) : x_(x) {} - Value() = delete; - Value(const Value&) = delete; - Value& operator=(const Value&) = delete; -private: - int x = 0; -}; -``` - -Например, если класс не подразумевает сравнения на равенство или других операторов -можно явно указать для них `delete`. - -### Методы - -Внутри класса можно определять функции, которые могут работать с полями класса, в том -числе закрытыми. Данные функции называются методы. - -Синтаксис аналогичен определению обычным функциям. - -Публичный метод можно вызвать через операторы `.` для экземпляра и `->` для указателяю. - -Приватные методы, можно вызывать внутри класса. - -Можно вызывать методы в списках инициализации. Например, метод, который будет -контролировать допустимость значения или выполнять дополнительные преобразования. - -### Определение методов вне класса - -Методы можно объявить внутри класса, а определить снаружи класса. Содержимое -класса имеет свою область видимости. Для определения снаружи класса перед именем -конструктора, метода, оператора используется имя класса и оператор разрешения области -видимости `::` - -```c++ -class Time { -public: - Time(); - Time(int hours, int minutes, int seconds = 0); - int GetHours(); - void SetHours(int hours); -private: - int hours_ = 0; - int minutes_ = 0; - int seconds_ = 0; -}; - -Time::Time() = default; -Time::Time(int hours, int minutes, int seconds) - : hours_(hours), minutes_(minutes), seconds_(seconds) {} - -int Time::GetHours() { return hours; } -void Time::SetHours(int hours) { hours_ += hours; } -``` - -Аргументы методов, имеющие значения по умолчанию указываются только при объявлении, -при определении нельзя указать значения по умолчанию - -### CV-квалификация методов - -Методы могут иметь CV-квалификацию. Методы, которые не изменяют полей класса, а только -предоставляют информацию о них следует помечать квалификатором `const` после сигнатуры -и перед телом метода: - -```c++ -class Size { -public: - size_t GetSize() const { return size; }; - void AddSize(size_t size) { size_ += size; }; -private: - size_t size_ = 0; -}; -``` - -Методы помеченные квалификатором `const` можно вызывать у константных объектов класса. -Компилятор отслеживает, что в данном методе нет измененеий полей класса. - -Методы можно перегрузить только по квалификатору `const`. - -Не изменяет поля класса и может быть вызван для константного объекта: - -```c++ -int Class::foo() const; -``` - -Может изменять поля класса и может быть вызван для `volatile` объекта: - -```c++ -int Class::foo() volatile; -``` - -Может быть вызван как для `const`, так и для `volatile` объекта, так и для -`const volatile` объекта: - -```c++ -int Class::foo() const volatile; -``` - -### Оператор преобразования - -В классе возможно определить оператор преобразования, который позволяет преобразовывать -пользовательский класс в другой тип. - -Синтаксис: ` operator () const {}` - -- `` - можно запретить неявное преобразование -- `` - тип к которому выполняется приведение - -Рекомендуется помечать `const` поскольку данный оператор не должен менять полей класса -и вызываться от констант данного класса. - -Как правило рекомендуется запрещать неявное преобразование к типу (использовать -`explicit`), поскольку можно обнаружить много неожиданных мест в коде, где неявно -произведено преобразование. - -Исключением обычно является оператор `bool` для удобства использования в условиях. - -### Перегрузка операторов внутри класса - -Поскольку первым аргументом неявно передается ключевое слово `this`, то перегрузка -бинарных операторов внутри класса имеет один аргумент: - -```c++ -Class& operator+=(const Class& other); -Class& operator-=(const Class& other); -Class& operator*=(const Class& other); -Class& operator/=(const Class& other); -``` - -Операторы арифмесстических операций часто переопределяют на основе работы присваивающих -операторов: - -```c++ -Class operator+(const Class& other) const { - Class result = *this; // copy ctor - result += other; // operator += - return result; -} -``` - -Операторы префиксного и постфиксного инкремента/декремента переопределяются -следующим образом: - -```c++ -Class& operator++(); // ++obj -Class operator++(int); // obj++ -Class& operator--(); // --obj -Class operator--(int); // obj-- -``` -- постфиксный оператор возвращает копию, поэтому у возвращаемого значения нет `&` - -### Перегрузка операторов вне класса - -Операторы можно перегрузить вне класса, тогда сигнатура перегружаемого оператора -пишется в привычной манере. Но для реализации таких операторов у класса должны быть -методы задающие и считывающие значение полей (геттеры и сеттеры). Бывает, что их нет, -тогда перегрузить класс не получится или получится на основе определенных операторов -составного присваивания внутри класса. - -Перегрузка инкремента и декремента вне класса: - -```c++ -Class& operator++(const Class& obj); // ++obj -Class operator++(const Class& obj, int); // obj++ -Class& operator--(const Class& obj); // --obj -Class operator--(const Class& obj, int); // obj-- -``` - -### Ключевое слово `friend` - -Внутри класса с помощью ключевого слова `friend` (_friend declaration_) можно -объявить дружественную функцию, класс или дружественный метод другого класса. - -Сущности объявленные дружественными будут иметь доступ к `private` и `protected` -полям класса. - -Дружественность работает в одностороннем порядке. - -```c++ -friend void SomeMethod(int); -friend struct SomeStruct; -friend class SomeClass; -friend OtherClass; // C++11 -friend int OtherClass::Method(); -``` - -### Ключевое слово `mutable` - -Спецификатор типа `mutable` разрешает изменять поле класса, объявленное с ним, -даже в константных методах и для константных объектов. - -Например, это может быть поле представляющее собой счетчик операций и необходимо его -изменять даже в константном методе. - -Также может использоваться в лямбда-выражениях \ No newline at end of file diff --git a/04_week/04_class.pdf b/04_week/04_class.pdf deleted file mode 100644 index 50a488d9..00000000 Binary files a/04_week/04_class.pdf and /dev/null differ diff --git a/04_week/CMakeLists.txt b/04_week/CMakeLists.txt index b15ca37c..0531237e 100644 --- a/04_week/CMakeLists.txt +++ b/04_week/CMakeLists.txt @@ -11,5 +11,5 @@ add_subdirectory(tasks) # Создать исполняемый файл для каждого примера if (BUILD_EXAMPLES_04_WEEK) -# add_example(class_examples ${EXAMPLES_DIR}/class_examples.cpp) +# add_example(struct_examples ${EXAMPLES_DIR}/struct_examples.cpp) endif() \ No newline at end of file diff --git a/04_week/tasks/stack/stack.cpp b/04_week/tasks/stack/stack.cpp index 222e4ffc..90e369ad 100644 --- a/04_week/tasks/stack/stack.cpp +++ b/04_week/tasks/stack/stack.cpp @@ -1,6 +1,58 @@ #include -class Stack { +class Stack { +public: + void Push(int value); + bool Pop(); + int& Top(); + const int& Top() const; + bool Empty() const; + size_t Size() const; + void Clear(); + void Swap(Stack& other); + bool operator==(const Stack& other) const{ + auto stack1 = (*this).stack_; + auto stack2 = other.stack_; + if (stack1.size() != stack2.size()) return false; + for (size_t i = 0; i < stack1.size(); ++i){ + if (stack1[i] != stack2[i]) return false; + } + return true; + } + bool operator!=(const Stack& other) const{ + return !(*this == other); + } +private: + std::vector stack_; }; + +void Stack::Push(int value){ + stack_.push_back(value); +} +bool Stack::Pop(){ + if (stack_.empty()) return false; + stack_.pop_back(); + return true; +} +const int& Stack::Top() const { + return stack_.back(); +} +int& Stack::Top() { + return stack_.back(); +} +bool Stack::Empty() const{ + return stack_.empty(); +} +size_t Stack::Size() const{ + return stack_.size(); +} +void Stack::Clear(){ + stack_.clear(); + stack_.shrink_to_fit(); +} +void Stack::Swap(Stack& other){ + stack_.swap(other.stack_); +} +