Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
С++.docx
Скачиваний:
26
Добавлен:
10.06.2015
Размер:
95.05 Кб
Скачать

64. Особенности определения и применения функций-операций «присваивание» в производных классах.

Проблема присваивания в рамках иерархии классов нужно рассматривать в 3-х аспектах:

  1. как присвоить объекту производного класса значения другого объекта этого же класса

  2. как присвоить объекту базового класса значение объекта производного класса

  3. как присвоить объекту производного класса значение объекта базового класса

Остановимся на 1-м аспекте. Рассмотрим 2 класса, в которых все специальные методы включая оператор присваивания неявно определяет компилятор:

class X {

public: int a; }

class Y: public X {

public: double b; };

Определим объекты производного класса и выполним операции над ними:

Y one, two; // сработает конструктор умолчания Y, из которого вызывается конструктор умолчания Х

one.a = 11;

one.b = 0.1

two = one; // сработает операция присваивания класса Y, из которого вызывается операция присваивания класса X

Убедимся, что все выполнено правильно.

cout << “two.a = “ << two.a << “\t two.b = “ << two.b << endl;

В данном примере нет необходимости явно определять операцию присваивания, так как функция операция неявно создается компилятором, все выполняется корректно, однако, возможна ситуация, когда явное определение операции присваивания необходима. Например, это нужно в случае ресурсоемких классов или когда значения полей производных классов рассчитываются по значению полей базовых классов.

Продолжим простой пример. Цель иллюстрации – понять как должна вызываться функция операция базового класса в производном классе.

Пусть при определении класса Y явно определяется функция операция присваивания.

class Y: public X { // (1)

public: double b; // (2)

Y & operator = (const Y & y1) { // (3)

if (this == & y1) return *this; // (4) страховка от самоприсваивания (this – константный указатель на объект передаваемый в нестатический метод вызываемый от имени этого объекта)

X:: operator = (dynamic)cast <const X &> (y1)); // (5) сначала вызываем в функциональной форме перегруженную операцию присваивания базового класса, которая правильно обрабатывает поле a

b = y1.b; // (6) здесь напрямую работаем с b

return *this; // (7)

} // (8)

}; // (9) конец класса Y

Так как функция операция должна получаться в качестве аргумента имеющая базовый класс, то фактический параметр должен иметь вид: (dynamic_cast <onst x &> (y1)) здесь применена операция предназначенная для преобразования базового класса.

Общий формат операции таков:

dynamic_cast <тип *> (выражение)

“< >” – обязательно

“(выражение)” – указатель или ссылка какого-то класса

“тип*” – или базовый, или производный для «класса»

В 1-м случае говорят, что осущ. повышающа преобраз. указат.

Во 2-м – понижающая преобраз. указат.

Таким образом, в нашем примере мы преобразуем ссылку на объект производного класса в ссылку на объект базового класса, и благодаря этому огбеспечивается корректный вызов функции операции базового класса.

65. Особенности перегрузки операций в производных классах.

Рассмотрим перегрузку вывода данных в стандартный поток. Этот пример интересен тем, что операция вывода/ввода нельзя перегружать с помощью операторов, чаще это делают при помощи дружественной функции. Дружественные функции, как и специальные методы не наследуются, а значит, возникает вопрос: «Как их перегрузить?»

Рассмотрим один из вариантов функции операции “<<”, в теле которой мы обратимся к аналогичной операции базового класса.

ostream & operator << (ostream & out, ellipse E1) {

out << dynaic_cast <const point &> (E1); // здесь мы обращаемся к перегруженной операции “<<” класса point

Далее мы работаем с полями класса ellipse

out << “оси элемента: “ << E1.rgor << “t\ E1.rvert = “ << E1 rvert << endl;

return out;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]