Лекции.Орг


Поиск:




Категории:

Астрономия
Биология
География
Другие языки
Интернет
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Механика
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Транспорт
Физика
Философия
Финансы
Химия
Экология
Экономика
Электроника

 

 

 

 


Перегрузка операторов. Оправданное и неоправданное использование. Пример перегрузки простейшего оператора. Операторы, которые нельзя перегружать




 

ПЕРЕГРУЗКА ОПЕРАТОРОВ (operator overloading) применяется как альтернатива функциям для пользовательских типов, которым в предметной области свойственен понятный однозначный синтаксис операций. Например, для сложения и умножения матриц вполне естественна и читабельна операторная форма выражений, хотя за этими элементарными на вид операциями скрываются алгоритмы с двойной и тройной вложенностью циклов соответственно:

 

D = A + B * C

 

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

 

Применение перегрузки операторов является необязательным, и для любого класса перегрузка операторов может быть заменена использованием обычных функций-членов. Если для реализуемого класса в предметной области операторный стиль является настолько естественным, как для матриц, перегрузка операторов существенно облегчает написание и чтение программ, использующих данный класс. Программист может предоставить собственную функцию, которая будет неявно вызываться при использовании оператора с объектами класса.

 

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

 

Нельзя перегружать операторы:

● “.” - доступ к члену структуры/класса;

● “.*” - доступ к члену структуры/класса через указатель на член;

● “::” - оператор разрешения области видимости;

● “?:” - тернарный условный оператор.

 

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

//пример перегрузки унарного оператора “!”

bool CoffeeMachine::operator! ()

{

if(GetGrainWeidhtLeft()<4)

return 0;

 

return 1;

}

 

13. Внутриклассовые и глобальные перегруженные операторы. Перегрузка операторов сдвига. Применение перегрузки сдвига для взаимодействия с потоками ввода/вывода.

● Внутриклассовый оператор ==:

 

class Date

{ // … без изменений …

public:

// Объявление внутриклассового оператора сравнения на равенство дат

bool operator == (const Date & d) const;

};

// Реализация внутриклассового оператора сравнения на равенство дат

inline bool Date::operator == (const Date & d) const

{

// Даты равны, когда все их компоненты равны между собой

return m_Year == d.GetYear() &&

m_Month == d.GetMonth() &&

m_Day == d.GetDay();

}

● Глобальный оператор ==:

 

// Реализация глобального оператора сравнения на равенство дат

inline bool operator == (const Date & d1, const Date & d2)

{

return d1.GetYear() == d2.GetYear() &&

d1.GetMonth() == d2.GetMonth() &&

d1.GetDay() == d2.GetDay();

}

 

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

 

Перегрузка операторов сдвига <<, >>

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

Когда появляться необходимость вывода объектов на консоль, имеет смысл перегрузить операторы сдвига для соответствующих классов, и получить согласованный синтаксис вывода.

Перегрузить оператор для вывода объектов пользовательских типов относительно легко. Такой оператор может быть только глобальным, внутриклассовый вариант исключается, поскольку первым операндом является сам объект-поток, а определение его класса уже нельзя никак расширить для пользовательского типа. Глобальные перегружаемые операторы таких проблем не имеют:

std::ostream& operator << (std::ostream& o, const Date & d)

{

o << d.GetYear() << ‘/’ << d.GetMonth() << ‘/’ << d.GetDay();

return o;

}

Возврат ссылки на поток необходим для дальнейшего каскадирования, т.е. для следующих вызовов <<, идущих в инструкции, использующей вывод для объектов классов.

Если требуется решить обратную задачу, а именно чтение объекта-даты из входного потока, нужно добавить подобные определения, однако передавать объект по ссылке с правом на запись:

std::istream & operator >> (std::istream & i, Date& d)

{ // Считываем строку до пробела

char buf[ 100 ];

i >> buf;

d = Date(buf); // используем имеющийся конструктор из строки, а затем копируем

return i;

}

int main ()

{ Date d;

std::cin >> d; //...

}

 

 





Поделиться с друзьями:


Дата добавления: 2016-07-29; Мы поможем в написании ваших работ!; просмотров: 813 | Нарушение авторских прав


Поиск на сайте:

Лучшие изречения:

Лаской почти всегда добьешься больше, чем грубой силой. © Неизвестно
==> читать все изречения...

2355 - | 2220 -


© 2015-2024 lektsii.org - Контакты - Последнее добавление

Ген: 0.009 с.