Программирование >>  Оптимизация возвращаемого значения 

1 ... 80 81 82 [ 83 ] 84 85 86 ... 96


class Lizard: public Animal { public:

LizardSc operator=(const Lizards rhs);

class Chicken: public Animal { public:

Chicken& operator=(const Chicken& rhs) ;

Здесь показаны только операторы присваивания, но этого пока более чем достаточно. Рассмотрим следующий код:

Lizard lizl; Lizard liz2;

Animal *pAnimall = &lizl; Animal *pAnimal2 = &liz2;

*pAnimall = *pAnimal2;

Здесь есть две проблемы. Во-первых, оператор присваивания, вызываемый в последней строке, принадлежит классу Animal, хотя объекты имеют тип Lizard. В результате, в объекте lizl будет изменена только часть класса Animal. Эточасттное присваивание. После присваивания члены класса Animal в объекте lizl будут иметь значения, полученные от 1 iz2, но члены класса Lizard в, останутся без изменений.

Вторая проблема состоит в том, что программисты действительно могут писать такой код. Опытные программисты С, перешедшие на С++, довольно часто выполняют присваивание объектам при помощи указателей. Поэтому надо сделать так, чтобы присваивание выполнялось более приемлемым образом. Как говорится в правиле 32, классы должно быть легко использовать правильно, и сложно - неправильно, а классы из вышеприведенной иерархии легко использовать неправильно.

Один из вариантов решения проблемы - сделать операторы присваивания виртуальными. Если бы функции Animal::operator= были виртуальными, то присваивание привело бы к вызову оператора присваивания класса Lizard, и такое поведение было бы корректным. Но посмотрите, что произойдет, если объявить операторы присваивания виртуальными:

class Animal { public:

virtual Animals operator=(const Animals rhs) ;

class Lizard: public Animal { public:

virtual Lizards operator=(const Animals rhs);



class Chicken: public Animal { public:

virtual ChickenSc operator=(const Animal& rhs)

Благодаря относительно недавним изменениям в языке можно сделать так, чтобы значение, возвращаемое каждым из операторов присваивания, было ссылкой на корректный класс, но правила языка С++ требуют объявлять идентичные типы параметров виртуальных функций во всех классах, в которых они объявлены. Это означает, что операторы присваивания в классах Lizard и Chicken должны быть готовы принять любой тип объектов Animal в правой части присваивания. Следовательно, надо 5итывать, что допустим подобный код:

Lizard liz;

Chicken chick;

Animal *pAnimall = &liz;

Animal *pAnimal2 = bchick;

*pAnimall = *pAnimal2;

Присвоить курице ящерицу!

Это смешанное присваивание: слева стоит объект типа Lizard, а справа -объект типа Chicken. Смешанные присваивания обычно не приводят к проблемам в С++, потому что благодаря строгой типизации языка они оказываются недопустимыми. Но, если оператор присваивания гсласса Animal стал виртуальным, появляется возможность таких смешанных операций присваивания.

Это ставит нас в сложное положение. Хотелось бы разрешить присваивание с помощью указателей одинаковых типов, запретив при этом смешанное присваивание посредством тех же самых указателей. Другими словами, разрешить:

Animal *pAnimall = &lizl; Animal *pAnimal2 = &liz2;

*pAnimall = *pAnimal2;

И запретить:

Animal *pAnimall = &liz; Animal *pAnimal2 = &chick;

Присвоить ящерицу ящерице.

*pAnimall = *pAnimal2;

Присвоить курицу ящерице.

Различить эти ситуации можно только во время выполнения программы, так как иногда допустимо присваивать *pAnimall значение *pAnimal2, а иногда нет. При этом вы вступаете в мрачный мир ошибок типа во время выполнения программы. В частности, вы должны сообщить об ошибке в функции operator=.



если столкнулись со смешанным присваиванием, если же типы одинаковы, надо выполнить присваивание как обычно.

Можно использовать для реализации такого поведения оператор dynamic cast (см. правило 2). Вот как это делается для оператора присваивания класса Lizard:

Lizards Lizard::operator=(const Animals rhs) {

Убедиться, что rhs имеет тип lizard, const Lizards rhs liz = dYnamic cast<const Lizards>(rhs); выполнить обычное присваивание *this значения rhs liz;

Данная функция присваивает объекту *this значение rhs, только если rhs имеет тип Lizard. Если это не так, то функция передает исключение bad cast, генерируемое оператором dynamic cast при неудачной попытке приведения типа. (На самом деле исключение имеет тип std: : bad cast, потому что компоненты стандартной библиотеки, включая генерируемые ими исключения, находятся в пространстве имен std. Обзор стандартной библиотеки см. в правиле 35.)

Даже если не беспокоиться об исключениях, эта функция кажется слишком сложной и требующей больших затрат: оператор dynamic cast должен обращаться к структуре type inf о, если один объект Lizard присваивается другому объекту того же типа (см. правило 24):

Lizard lizl, liz2;

lizl = liz2; Нет необходимости применять

dYnamic cast; это присваивание должно быть допустимо.

Чтобы при обработке этого случая избежать чрезмерного усложнения кода или применения оператора dynamic cast, надо добавить к классу Lizard обычный оператор присваивания:

class Lizard: public Animal { public:

virtual Lizards operator=(const Animals rhs) ;

Lizards operator=(const Lizards rhs); Добавить это.

Lizard lizl, liz2;

lizl = liz2; Вызов operator=

с аргументом const izards.

Animal *pAnimall = Slizl; Animal *pAnimal2 = Sliz2;

*pAnimall = *pAnimal2; Вызов operator=

с аргументом const Animals.



1 ... 80 81 82 [ 83 ] 84 85 86 ... 96

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика