|
Программирование >> Дополнительные возможности наследования
Например, класс CAT содержит переменную-член theCat, которая указывает на ячейку в области динамической памяти, где сохранено некоторое целочисленное значение. Копировщик по умолчанию скопирует переменную theCat из старого класса CAT в переменную theCat в новом классе CAT. При этом оба объекта будут указывать на одну и ту же ячейку памяти (рис. 10.1). Область динамического обмена старый рсласс cat itsAge новый рсласс CAT itsAge Рис. 10.1. Использование копировщика, заданного по умолчанию Проблемы могут возникнуть, если программа выйдет за область видимости одного из классов CAT. Как уже отмечалось при изучении указателей, назначение деструктора состоит в том, чтобы очищать память от ненужных объектов. Если деструктор исходного класса CAT очистит свои ячейки памяти, а объекты нового класса CAT все так же будут ссылаться на эти ячейки, то над профаммной нависнет смертельная опасность. Эта проблема проиллюстрирована на рис. 10.2. Область динамического обмена Рис. 10.2. Возникновение ошибочного указателя Чтобы предупредить возникновение подобных проблем, нужно вместо копировщика по умолчанию создать и использовать собственный копировщик, который будет осуществлять глубинное копирование с перемещением значений переменных-членов в новые адреса памяти. Этот процесс показан в листинге 10.5 Аистинг 10.5. Консшрукшор-копировщпк 2 3 4 5 6 7 Листинг 10.5. Конструктор-копировщик ftinclude <iostream.h> class CAT < public; CATO; CAT (const CAT &); конструктор no умолчанию конструктор-копировщик 11: CATO; деструктор 12; int GetAgeO const { return *itsAge; } 13: int GetWeightO const { return *itsWeight; } 14: void SetAge(int age) { *itsAge = age; } 16: private: 17: int *itsAge; 18: int itsWeight; 19: } ; 21: CAT:: CATO 22: { 23: itsAge = new int; 24: itsWeight = new int; 25: .itsAge = 5; 26: .itsWeight = 9; 27: } 28: 29: CAT::CAT(const CAT & rhs) 30: { 31: itsAge = new int; 32; itsWeight = new int; 33: .itsAge = rhs.GetAge(); открытый метод доступа 34: .itsWeight = .(rhs.itsWeight); закрытый метод доступа 35: } 36: 37; CAT::-CAT О 38: { 39: delete itsAge; 40: itsAge = 0; 41: delete itsWeight; 42; itsWeight = 0; 43: } 45: int mainO 46: { 47: CAT frisky; 48: cout friskys age: frisky.GetAgeO endl; 49: cout Setting frisky to 6...\ n ; 50; frisky.SetAge(6); 51; cout Creating boots from frlsky\ n ; 52: CAT boots(frisky); 53: cout friskys age: << frisky.GetAgeO << endl; 54: cout boots age: boots. GetAgeO endl; 55: cout setting frisky to 7...\ n ; 56: frisky.SetAge(7); 57: cout friskys age; frisky.GetAgeO endl; 58: cout boots age: boots.GetAgeO endl; 59: return 0; 60: } ЕИ! friskys age: 5 Setting frisky to 6,. . Creating boots from frisky friskys age: 6 boots age: 6 setting frisky to 7... friskys age: 7 boots age: 6 В строках профаммы с 6 по 19 объявляется класс CAT. Обратите внимание, что в строке 9 объявляется конструктор по умолчанию, а в строке 10 - конструктор-копировщик. В строках 17 и 18 объявляется две переменные-члены, представляющие собой указатели на целочисленные значения. В реальной жизни трудно вообразить, для чего может понадобиться создание переменных-членов как указателей на целочисленные значения. Но в данном случае такие переменные являются отличными объектами для демонстрации методов управления переменными-членами, сохраненными в динамической области памяти. Конструктор по умолчанию в строках с 21 по 27 въщеляет для переменных области динамической памяти и инициализирует эти переменные. Работа копировщика начинается со строки 29. Обратите внимание, что в копировщике задан параметр rhs. Использовать в параметрах копировщиков символику rhs, что означает right-hand side (стоящий справа), - общепринятая практика. Если вы посмотрите на строки 33 и 34, то увидите, что в выражениях присваивания имена параметров копировщика располагаются справа от оператора присваивания (знака равенства). Вот как работает копировщик. Строки 31 и 32 выделяют свободные ячейки в области динамической памяти. Затем, в строках 33 и 34 в новые ячейки переписываются значения из существующего класса CAT. Параметр rhs соответствует объекту классу CAT, который передается в копировщик в виде константной ссылки. Как объект класса CAT, rhs содержит все переменные-члены любого другого класса CAT. Любой объект класса CAT может открыть доступ к закрьпъш переменным-членам для любого другого объекта класса CAT. В то же время для внеиших обращений всегда лучше создавать открьпые члены, где это только возможно. Функция-член rhs. GetAgeO юзвраща-ет значение, сохраненное в переменной-члене itsAge, адрес которой представлен в rhs. Процедуры, осуществляемые профаммой, продемонстрированы на рис. 10.3. Значение, на которое ссылалась переменная-член исходного класса CAT, копируется в новую ячейку памяти, адрес которой представлен в такой же переменной-члене нового класса CAT. В строке 47 вызывается объект frisky из класса CAT. Значение возраста, заданное в frisky, выводится на экран, после чего в строке 50 переменной возраста присваивается новое значение - 6. В строке 52 методом копирования объекта frisky создается новый объект boots класса CAT. Если бы в качестве параметра передавался объект frisky, то вызов копировщика осуществлялся бы компилятором. В строках 53 и 54 выводится возраст обеих кошек. Обратите внимание, что в обоих случаях в объектах frisky и boots записан возраст 6, тогда как если бы объект boots создавался не методом копирования, то по умолчанию было бы присвоено значение 5. В строке 56 значение возраста в объекте бьию изменено на 7 и вновь выведены на экран значения обоих объектов. Значение объекта frisky действительно изменилось на 7, тогда как в boots сохранилось прежнее значение возраста 6. Это доказывает, что переменная объекта frisky была скопирована в объект boots по новому адресу.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |