Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Мизрохи С.В. -> "Turbo Pascal и объектно-ориентированное программирование" -> 34

Turbo Pascal и объектно-ориентированное программирование - Мизрохи С.В.

Мизрохи С.В. Turbo Pascal и объектно-ориентированное программирование — М.: Финансы и статистика , 1992. — 192 c.
ISBN 5-279-00903-2
Скачать (прямая ссылка): efektispolzc2000.djvu
Предыдущая << 1 .. 28 29 30 31 32 33 < 34 > 35 36 37 38 39 40 .. 105 >> Следующая

return *this; Il См. правило 15.
}
Рассмотрим, что получится в этом случае:
String а = "Hello"; а = а;
// То же, что и a.operator= (а)
Внутри оператора присваивания *this и rhs на первый взгляд кажутся разными объектами, но в данном случае они являются различными идентификатора-Ми одного и того же объекта. Вы можете представить себе это следующим образом:
Конструкторы и операторы
Первое, что делает оператор присваивания, - вызывает delete для указателя datadelete, в результате чего мы приходим к следующему положению вещей:
Теперь результат применения Strien к rhs .data в операторе присваивания не определен. Это объясняется тем, что при удалении data мы удалили rhs . data, поскольку data, this->data и rhs .data - один и тот же указатель! Далее неприятности только множатся.
Решение проблемы - проверка на присваивание самому себе и немедленный выход в этом случае. К сожалению, о такой проверке гораздо легче говорить, чем ее сделать, ибо сразу возникает вопрос, какие объекты считать «одинаковыми».
Проблема, с которой мы сталкиваемся, известная как тождественность объектов, - популярная тема объектного программирования. В задачу автора не входит написание трактата о тождественности объектов; тем не менее есть смысл упомянуть два основных подхода к данному вопросу.
Один подход заключается в том, чтобы считать два объекта одинаковыми (тождественными), если они имеют одинаковое значение. Например, два объекта String будут одинаковыми, если содержат идентичный набор символов:
String а = "Hello"; String b - "World"; String с = "Hello";
Здесь а и с имеют одно и то же значение, поэтому их можно считать тождественными, a b отлично от них обоих. Если в нашем классе String использовать это определение тождественности, оператор присваивания мог бы выглядеть следующим образом:
Strings String::operator=(const Strings rhs) {
if (strcmp(data, rhs.data) == 0) return *this;
Равенство значений обычно определяет operator==, поэтому общая форма для оператора присваивания класса С, реализующего тождественность в смысле равенства значений объектов, будет следующей:
С& С: :operator= (const CSc rhs)
11 Проверка на присваивание себе. if (*this == rhs) Il Предполагается, что operator== определен.
равило 17
return *this;
Обратите внимание, что эта функция сравнивает объекты (посредством erator==), а не указатели. При использовании тождественности по значению не важно, занимают ли оба объекта одну и ту же память: единственное, что принимается во внимание, - это содержащиеся в ней значения.
Другая возможность - определять тождественность объектов по их адресам в памяти. При использовании этого определения равенства объектов два объекта тождественны тогда и только тогда, когда они имеют один адрес. Это определение более распространено в программах на С++, возможно потому, что его легко реализовать, и необходимые вычисления выполняются быстро. Эти два преимущества не всегда достижимы, если тождественность определяется по значениям. При использовании эквивалентности адресов общий вид оператора присваивания имеет следующую форму:
С& С: :operator= (const С& rhs) ' \
{
// Проверка на присваивание себе, if (this == &rhs) return *this;
}
Для большинства программ это вполне приемлемо.
Если вам необходим более изощренный механизм определения эквивалентности объектов, вам придется реализовывать его самим. Наиболее часто используемый подход основан на использовании функции-члена, возвращающей некоторый идентификатор объекта:
class С { public:
ObjectID identityO const; I / См. также правило 36.
В этом случае, имея два указателя на объекты а и Ь, мы считаем объекты, на которые они указывают, тождественными только в том случае, если а->identity () s b->ident і ty (). При этом, разумеется, в вашу задачу входит написание функции operator== для ObjectID.
Проблема совмещения имен и тождественности объектов не ограничивается оператором присваивания. Просто это функция, для которой возникновение дан-Ной проблемы наиболее вероятно. При наличии ссылок и указателей любые два объекта совместимого типа могут в действительности ссылаться на один и тот же объект. Вот еще несколько ситуаций, в которых совмещение имен может создать существенные трудности:
class Base {
void mfl(Base& rb) ; Il rb и *this могут совпадать.
¦¦1Ii
Конструкторы и операторы
};
void fl(Bases rbl,Bases rb2); class Derived: public Base {
Il rbl и rb2 могут совпадать.
void mf2(Bases rb);
Il rb и *this могут совпадать.
};
int f2(DerivedS rd, Bases rb) ; II rd и rb могут совпадать.
В этих примерах используются ссылки, но вполне могли бы подойти и указатели.
Как видите, совмещение может принимать множество форм, так что не стоит забывать о нем, надеясь, что вы никогда с ним не столкнетесь. Впрочем, может быть, лично вам это удастся, но большинству программистов - нет. Образно выражаясь, это именно тот случай, когда предосторожность ценится на вес золота. Всякий раз, когда вы создаете функцию, в которой возможно совмещение имен, вам следует учитывать такую возможность при написании кода.
Предыдущая << 1 .. 28 29 30 31 32 33 < 34 > 35 36 37 38 39 40 .. 105 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100