1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
//Листинг #1 Основа для дальнейшего объяснения clang #include <cstring> #include <iostream> using std::ostream; using std::cout; class MyString{ char *str; public: MyString(); //прототип конструктора по умолчанию ~MyString(); //прототип деструктора MyString(const char*); //прототип конструктора с параметром friend ostream& operator << (ostream& , const MyString&); //прототип перегрузки << }; MyString::MyString(){ str = new char[255]; str[0] = 0; //нуль-символ, имитируем пустую строку } MyString::~MyString(){ delete []str; } MyString::MyString(const char* S){ str = new char[255]; strcpy(str, S); //копируем строку извне вовнутрь класса } ostream& operator << (ostream& os, const MyString& S){ return os << S.str; } int main(){ MyString S1("Hello world"); MyString S2; cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; } |
1 2 3 4 5 6 7 8 9 10 11 12 |
//Дополняем main, проверяя операцию присваивания int main(){ MyString S1("Hello world"); MyString S2; cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; S1 = S2; //несмотря на то, что это работает cout << S1 << '\n'; //программа запускается, но эта строчка способна свалить программу, т. е. работает безобразно } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
//Листинг #2 Перегрузка операции присваивания clang #include <cstring> #include <iostream> using std::ostream; using std::cout; class MyString{ char *str; public: MyString(); ~MyString(); MyString(const char*); friend ostream& operator << (ostream& , const MyString&); MyString& operator = (const MyString&); //прототип перегрузки операции = }; MyString::MyString(){ str = new char[1]; str[0] = 0; } MyString::~MyString(){ delete []str; } MyString::MyString(const char* S){ str = new char[255]; strcpy(str, S); } ostream& operator << (ostream& os, const MyString& S){ return os << S.str; } /* РЕАЛИЗАЦИЯ ПЕРЕГРУЗКИ ОПЕРАЦИИ ПРИСВАИВАНИЯ */ MyString& MyString::operator=(const MyString& S){ if (this == &S) return *this; //Если попытка присвоиться в себя, то сразу выходим, отдавая ссылку на самого себя delete []str; //зачищаем строку нынешнего объекта size_t len = strlen(S.str) + 1; //узнаём длину копируемой строки, учитываем нуль-символ str = new char[len]; //выделяем память, столько же, сколько у копируемой строки strncpy(str, S.str, len); //копируем в новорожденную строку значения из присваиваемой в неё строку return *this; //отдаём назад ссылку на самого себя } int main(){ MyString S1; MyString S2("Hello world"); cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; S1 = S2; //благодаря явной перегрузке операции присваивания эта строчка теперь выполняет свою работу как надо cout << "\noperation: S1 = S2" << '\n'; cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
//Листинг #3 Перегрузка операции присваивания Идиома copy-and-swap C++11 clang #include <cstring> #include <iostream> using std::ostream; using std::cout; class MyString{ char *str; public: MyString(); ~MyString(); MyString(const char*); MyString(const MyString&); //прототип конструктора копирования friend ostream& operator << (ostream& , const MyString&); MyString& operator = (MyString&); //прототип перегрузки операции = void swap(MyString &) noexcept; //прототип функции swap (не бросающего исключений) }; MyString::MyString(){ str = new char[1]; str[0] = 0; } MyString::~MyString(){ delete []str; } MyString::MyString(const char* S){ str = new char[255]; strcpy(str, S); } /* РЕАЛИЗАЦИЯ КОНСТРУКТОРА КОПИРОВАНИЯ */ MyString::MyString(const MyString& S){ size_t len = strlen(S.str) + 1; str = new char[len]; strncpy(str, S.str, len); } ostream& operator << (ostream& os, const MyString& S){ return os << S.str; } /* РЕАЛИЗАЦИЯ ПЕРЕГРУЗКИ ОПЕРАЦИИ ПРИСВАИВАНИЯ */ MyString& MyString::operator=(MyString& S){ if (this == &S) return *this; //Если попытка присвоиться в себя, то сразу выходим, отдавая ссылку на самого себя MyString tmp(S); //создаём временный объект this->swap(S); //меняем местами значения временного объекта со знаениям настоящего объекта return *this; //отдаём назад ссылку на самого себя } /* РЕАЛИЗАЦИЯ ОБМЕНА ЗНАЧЕНИЙ */ void MyString::swap(MyString &S) noexcept{ std::swap(S.str, str); //меняем местами значения присваимаего объекта и объекта, в который присваивается присваиваемый объект } int main(){ MyString S1; MyString S2("Hello world"); cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; MyString S3(S2); cout << "S3 == " << S3 << '\n'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
//Листинг #4 Ненадёжная реализация перегрузки операции присваивания: явный вызов деструктора и применение new на перераспределение памяти + копирование #include <cstring> #include <iostream> using std::ostream; using std::cout; class MyString{ char *str; public: MyString(); ~MyString(); MyString(const char*); MyString(const MyString&); //прототип конструктора копирования friend ostream& operator << (ostream& , const MyString&); MyString& operator = (MyString&); //прототип перегрузки операции = }; MyString::MyString(){ str = new char[1]; str[0] = 0; } MyString::~MyString(){ delete []str; } MyString::MyString(const char* S){ str = new char[255]; strcpy(str, S); } /* РЕАЛИЗАЦИЯ КОНСТРУКТОРА КОПИРОВАНИЯ */ MyString::MyString(const MyString& S){ size_t len = strlen(S.str) + 1; str = new char[len]; strncpy(str, S.str, len); } ostream& operator << (ostream& os, const MyString& S){ return os << S.str; } /* РЕАЛИЗАЦИЯ ПЕРЕГРУЗКИ ОПЕРАЦИИ ПРИСВАИВАНИЯ */ MyString& MyString::operator=(MyString& S){ if (this == &S) return *this; //Если попытка присвоиться в себя, то сразу выходим, отдавая ссылку на самого себя this-> ~MyString(); //явно вызываем деструктор для настоящего объекта new (this) MyString(S); //и тут же выделяем новую память настоящему объекту и копируем в неё состояние присваиваемого объекта return *this; //отдаём назад ссылку на самого себя } int main(){ MyString S1; MyString S2("Hello world"); cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; S1 = S2; cout << "\noperation: S1 = S2:\n"; cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
//Листинг #5 Перегрузка операции присваивания C++11 clang #include <cstring> #include <iostream> using std::ostream; using std::cout; class MyString{ char *str; public: MyString(); ~MyString(); MyString(const char*); MyString(const MyString&); //прототип конструктора копирования friend ostream& operator << (ostream& , const MyString&); void swap(MyString& other); //прототип функции перемены мест элементов MyString(MyString&& other); //прототип конструктора переноса MyString& operator=(MyString other); //прототип функции-перегрузки операции присваивания }; MyString::MyString(){ str = new char[1]; str[0] = 0; } MyString::~MyString(){ delete []str; } MyString::MyString(const char* S){ str = new char[255]; strcpy(str, S); } /* РЕАЛИЗАЦИЯ КОНСТРУКТОРА КОПИРОВАНИЯ */ MyString::MyString(const MyString& S){ size_t len = strlen(S.str) + 1; str = new char[len]; strncpy(str, S.str, len); } ostream& operator << (ostream& os, const MyString& S){ return os << S.str; } /* РЕАЛИЗАЦИЯ ОБМЕНА ЭЛЕМЕНТАМИ */ void MyString::swap(MyString& other) { std::swap(str, other.str); } MyString::MyString(MyString&& other) // конструктор копирования из rvalue, он же конструктор переноса { this->swap(other); } /* РЕАЛИЗАЦИЯ ОПЕРАЦИИ ПРИСВАИВАНИЯ */ MyString& MyString::operator=(MyString other) { // передача параметра по значению важна! this->swap(other); // обмен с временной копией return *this; } int main(){ MyString S1; MyString S2("Hello world"); cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; S1 = S2; cout << "\noperation: S1 = S2:\n"; cout << "S1 == " << S1 << '\n'; cout << "S2 == " << S2 << '\n'; } |
Добавить комментарий