- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Освой самостоятельно за 21 день - Джесс Либерти
Шрифт:
Интервал:
Закладка:
Рекомендуется:Перегружайте операторы, если код программы после этого станет четче и понятнее. Возвращайте объекты класса из перегруженных операторов.
Не рекомендуется:Не увлекайтесь созданием перегруженных операторов, выполняющих несвойственные им функции.
Оператор присваивания
Четвертая, и последняя, функция, предоставляемая компилятором для работы с объектами, если, конечно, вы не задали никаких дополнительных функций, это функция оператора присваивания (operator=()). Этот оператор используется всякий раз, когда нужно присвоить объекту новое значение, например:
CAT catOne(5,7);
CAT catTwo(3,4);
//...другие строки программы
catTwo = catOne
В данном примере создан объект catOne, переменной которого itsAge присвоено значение 5, а переменной itsWeigth — 7. Затем создается объект catTwo со значениями переменных соответственно 3 и 4.
Через некоторое время объекту catTwo присваиваются значения объекта catOne. Что произойдет, если переменная itsAge является указателем, и что происходит со старыми значениями переменных объекта catTwo?
Работа с переменными-членами, которые хранят свои значения в области динамической памяти, рассматривалась ранее при обсуждении использования конструктора- копировщика (см. также рис. 10.1 и 10.2).
В C++ различают поверхностное и глубинное копирование данных. При поверхностном копировании происходит передача только адреса от одной переменной к другой, в результате чего оба объекта указывают на одни и те же ячейки памяти. В случае глубинного копирования действительно происходит копирование значений переменных из одной области памяти в другую. Различия между этими методами копирования показаны на рис. 10.3.
Все вышесказанное справедливо для присвоения данных. В случае использования оператора присваивания, процесс обмена данных протекает с некоторыми особенностями. Так, объект catTwo уже существует вместе со своими переменными, для каждой из которых выделены определенные ячейки памяти. В случае присвоения объекту новых значений предварительно необходимо освободить эти ячейки памяти. Что произойдет, если выполнить присвоение объекта catTwo самому себе:
catTwo = catTwo
Вряд ли такая строка в программе может иметь смысл, но в любом случае программа должна уметь поддерживать подобные ситуации. Дело в том, что присвоение объекта самому себе может произойти по ошибке в случае косвенного обращения к указателю, который ссылается на тот же объект.
Если не предусмотреть поддержку такой ситуации, то оператор присваивания сначала очистит ячейки памяти объекта catTwo, а затем попытается присвоить объекту catTwo свои собственные значения, которых уже не будет и в помине.
Чтобы предупредить подобную ситуацию, ваш оператор присваивания прежде всего должен определить, не совпадают ли друг с другом объекты по обе стороны от оператора присваивания. Это можно осуществить с помощью указателя this, как показано в листинге 10.15.
Листинг 10.15. Оператор присваивания
1: // Листинг 10.15.
2: // Конструктор-копировщик
3:
4: #include <iostream.h>
5:
6: class CAT
7: {
8: public:
9: CAT(); // конструктор по умолчанию
10: // конструктор-копировщик и деструктор пропущены!
11: int GetAge() const { return *itsAge; }
12: int GetWeight() const { return *itsWeight; }
13: void SetAge(int age) { *itsAge = age; }
14: CAT & operator=(const CAT &);
15:
16: private:
17: int *itsAge;
18: int *itsWeight;
19: };
20:
21: CAT::CAT()
22: {
23: itsAge = new int;
24: itsWeight = new int;
25: *itsAge = 5;
26: *itsWeight = 9;
27: }
28:
29:
30: CAT & CAT::operator=(const CAT & rhs)
31: {
32: if (this == &rhs)
33: return *this;
34: *itsAge = rhs.GetAge();
35: *itsWeight = rhs.GetWeight();
36: return *this;
37: }
38:
39:
40: int main()
41: {
42: CAT frisky;
43: cout << "frisky's age: " << frisky.GetAge() << endl;
44: cout << "Setting frisky to 6...n";
45: frisky.SetAge(6);
46: CAT whiskers;
47: cout << "whiskers' age: " << whiskers.GetAge() << endl;
48: cout << "copying frisky to whiskers...n";
49: whiskers = frisky;
50: cout << "whiskers' age: " << whiskers.GetAge() << endl;
51: return 0;
52: }
Результат:
frisky's age: 5
Setting frisky to 6. . .
whiskers' age: 5
copying frisky to whiskers...
whiskers' age: 6
Анализ: В листинге 10.15 вновь используется класс CAT. Чтобы не повторяться, в данном коде пропущены объявления конструктора-копировщика и деструктора. В строке 14 объявляется оператор присваивания, определение которого представлено в строках 30—37.
В строке 32 выполняется проверка того, не является ли объект, которому будет присвоено значение, тем же самым объектом класса CAT, чье значение будет присвоено. Чтобы проверить это, сравниваются адреса в указателях rhs и this.
Безусловно, оператор присваивания (=) может быть произвольно перегружен таким образом, чтобы отвечать представлениям программиста, что означает равенство объектов.
Операторы преобразований
Что происходит при попытке присвоить значение переменой одного из базовых типов, таких как int или unsigned short, объекту класса, объявленного пользователем? В листинге 10.16 мы опять вернемся к классу Counter и попытаемся присвоить объекту этого класса значение переменной типа int.
Предупреждение:Листинг 10.16 не компилируйте!
Листинг 10.16. Попытка присвоить объекту класса Counter значение переменной типа int
1: // Листинг 10.16.
2: // Эту программу не компилируйте!
3:
4: int
5: #include <iostream.h>
6:
7: class Counter
8: {
9: public:
10: Counter();
11: ~Counter(){ }
12: int GetItsVal()const { return itsVal; }
13: void SetItsVal(int x) { itsVal = x; }
14: private:
15: int itsVal;
16:
17: };
18:
19: Counter::Counter():
20: itsVal(0)
21: { }
22:
23: int main()
24: {
25: int theShort = 5;
26; Counter theCtr = theShort;
27: cout << "theCtr: " << theCtr.GetItsVal() << endl;
28: return 0;
29: }
Результат:
Компилятор покажет сообщение об ошибке, поскольку не сможет преобразовать тип int в Counter.
Анализ: Класс Counter, определенный в строках 7—17, содержит только один конструктор, заданный по умолчанию. В нем не определено ни одного метода преобразования данных типа int в тип Counter, поэтому компилятор обнаруживает ошибку в строке 26. Компилятор ничего не сможет поделать, пока не получит четких инструкций, что данные типа int необходимо взять и присвоить переменной-члену itsVal.
В листинге 10.17 эта ошибка исправлена с помощью оператора преобразования типов. Определен конструктор, который создает объект класса Counter и присваивает ему полученное значение типа int.
Листинг 10.17. Преобразование int в Counter
1: // Листинг 10.17.
2: // Использование конструктора в качестве оператора преобразования типа
3:
4: int
5: #include <iostream.h>
6:
7: class Counter
8: {
9: public:
10: Counter();
11: Counter(int val);
12: ~Counter(){ }
13: int GetItsVal()const { return itsVal; }
14: void SetItsVal(int x) { itsVal = x; }
15: private:
16: int itsVal;
17:
18: };
19:
20: Counter::Counter():
21: itsVal(0)
22: { }
23:
24: Counter::Counter(intval):
25: itsVal(val)
26: { }
27:
28:
29: int main()
30: {
31: int theShort = 5;
32: Counter theCtr = theShort;
33: cout << "theCtr: " << theCtr.GetItsVal() << endl;
34: return 0;
35: }
Результат:
the Ctr: 5
Анализ: Важные изменения произошли в строке 11, где конструктор перегружен таким образом, чтобы принимать значения типа int, а также в строках 24—26, где данный конструктор применяется. В результате выполнения конструктора переменной-члену класса Counter присваивается значение типа int.
Для присвоения значения программа обращается к конструктору, в котором присваиваемое значение передается в качестве аргумента. Процесс осуществляется в несколько шагов.
Шаг 1: создание переменной класса Counter с именем theCtr.
Это то же самое, что записать: int x = 5, где создается целочисленная переменная x и ей присваивается значение 5. Но в нашем случае создается объект theCtr класса Counter, который инициализируется переменной theShortTHna short int.
Шаг 2: присвоение объекту theCtr значения переменной theShort.
Но переменная относится к типу short, а не Counter! Первое, что нужно сделать, — это преобразовать ее к типу Counter. Компилятор может делать некоторые преобразования автоматически, но ему нужно точно указать, чего от него хотят. Именно для инструктирования компилятора создается конструктор класса Counter, который содержит единственный параметр, например типа short: