Лекция 13. Введение в ООП. Часть 4 Красс Александр Alexander.Krass@gmail.com СПбГУ ИТМО, 2008.

Презентация:



Advertisements
Похожие презентации
Лекция 10. Введение в ООП. Часть 3 Красс Александр СПбГУ ИТМО, 2008.
Advertisements

Лекция 11. Введение в ООП. Часть 4 Красс Александр СПбГУ ИТМО, 2008.
Лекция 12 Перегрузка операторов. Часть 2. Подбельский гл. 9.7, Страуструп гл. 11, Мейрс п. 11,15-17,19. Перегрузка копирующего конструктора T(const T&)
Лекция 18. Повторение и введение в STL (часть 1) Красс Александр СПбГУ ИТМО, 2008.
Лекция 9. Введение в ООП. Часть 2 Красс Александр СПбГУ ИТМО, 2008.
1 Переопределение операций Макаревич Л. Г.. 2 Зачем нужна перегрузка операций? class Complex { double re; double im; public: Complex(double r=0, double.
Прикладное программирование кафедра прикладной и компьютерной оптики Полиморфизм.
Лекция 21. Шаблоны (часть 1) Красс Александр СПбГУ ИТМО, 2008.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Лекция 31. Динамическая информация о типе Красс Александр СПбГУ ИТМО, 2009.
Лекция 8. Введение в ООП. Часть 1 Красс Александр СПбГУ ИТМО, 2008.
Статические поля класса Статические поля хранят данные, общие для всех элементов класса. Статическое поле существует в единственном экземпляре для всех.
Потоки Язык C++ не обеспечивает средств для ввода/вывода Ему это и не нужно; такие средства легко и элегантно можно создать с помощью самого языка Традиционно.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
Лекция 22. Шаблоны (часть 2) Красс Александр СПбГУ ИТМО, 2008.
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Лекция 10 Класс как абстрактный тип. Подбельский гл. 9, Страуструп гл. Конструкторы и деструктор Конструкторы - это специальные функции-члены класса, предназначенные.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Работа с файлами Сазонов Д.О. ПМиЭММ Часть 2. Тема занятия: Работа с файлами через потоки Для реализации файлового ввода/вывода, необходимо включить в.
©ρŧą Базовые конструкции языка.
Транксрипт:

Лекция 13. Введение в ООП. Часть 4 Красс Александр СПбГУ ИТМО, 2008

2 Тема "Перегрузка операторов"

3 Перегрузка операторов При проектировании класса вы можете предоставить набор операторов, для которых будет определена семантика работы с этим классом. Это реализуется с помощью перегрузки операторов. Для этого необходимо реализовать функцию следующего вида: Тип - знак операции. Перегрузка операторов не более чем "синтаксический сахар"

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

5 Перегрузка операторов Вы можете перегружать почти все операторы кроме : ::.*. ?: Вы не можете перегрузить операторы для стандартных типов. Вы не можете добавлять новые операторы (Например, % для вычисления экспоненты). Вы не можете превратить бинарный оператор в унарный.

6 Бинарные операторы Бинарный оператор может быть реализован или как функция-член с одним аргументом, или как глобальная функция с двумя аргументами Пример (оператор сложения): Имеем выражение a + b. Оно будет превращено в – a.operator+(b), если operator+ – функция член. – или в operator+(a, b), если operator+ – это глобальная функция.

7 Унарные операторы Унарный оператор может быть реализован или как функция-член без аргументов или как глобальная функция с одним аргументом Пример (оператор изменения знака): Имеем выражение -a. Оно будет превращено в – a.operator-(), если operator- – функция член, –или в operator-(a), если operator- – это глобальная функция.

8 Перегрузка операторов Пример перегрузки через функции-члены: class X { X* operator& (); // унарный & // (взятие адреса) X operator& (X); // бинарный & (и) X operator& (X, X); // ошибка: тернарный & X operator/ (X, X); // ошибка: тернарный / };

9 Перегрузка операторов Перегрузка через глобальные функции: X operator- (X); // унарный минус X operator- (X,X); // бинарный минус X operator- (); // ошибка: нет // операнда X operator- (X, X, X); // ошибка: //тернарный // оператор - X operator% (X); // ошибка: унарный // оператор %

10 String class String { public: String(); String(const char* s = NULL); String(const String& s); ~String (); String& operator= (const String& s); String operator+ (const String& s); char& operator[] (int element); int length () const; // length private: char* data; };

11 Операция конкатенации Операция конкатенации (через функцию-член): String String::operator+ (const String& s) { String temp; temp.data = new char[strlen(data) + strlen(s.data) + 1]; strcpy(temp.data, data); strcat(temp.data, s.data); return temp; }

12 Операция конкатенации Операция конкатенации должна поддерживать следующие формы записи: 1. String + String 2. String + "a C string" 3."a C string" + String 4."a C string" + "a C string" 5. String += String 6. String += "a C string"

13 Операция конкатенации void main () { String a ("Hello"); String b (" world"); String c, d; c = a + b; cout << c.ToChars() << endl;// На экране: d = a + " world"; // Hello world cout << d.ToChars() << endl;// Hello world }

14 Операция конкатенации Первые два варианта использования мы поддерживаем. В выражении d = a + " hello" строка " hello" неявно конвертируется в класс String с помощью конструктора String (const char* s). При выполнении этой строки компилятор создаст временную переменную и вызовет для нее этот конструктор. Следовательно, мы не обязаны реализовывать второй вариант оператора, со следующим прототипом: String operator+(const char *s); Хотя это и было бы эффективнее.

15 Операция конкатенации Операция конкатенации должна поддерживать следующие формы записи: 1. String + String 2. String + "a C string" 3."a C string" + String 4."a C string" + "a C string" 5. String += String 6. String += "a C string"

16 Операция конкатенации При попытке написать: String e = "Hello" + b; cout << e.ToChars() << endl; мы получим ошибку. Этот код как бы эквивалентен вызову "Hello".operator+(b);

17 Операция конкатенации Для поддержки третьего сценария надо использовать глобальную функцию String operator+ (const String& a, const String& b); Она должна быть объявлена как friend

18 Операция конкатенации class String {... friend String operator+ (const String& a, const String& b);... }; Функцию член в этом случае можно убрать

19 Операция конкатенации String operator+ (const String& a, const String& b) { String temp; temp.data = new char[strlen (a.data) + strlen (b.data) + 1]; strcpy(temp.data, a.data); strcat(temp.data, b.data); return temp; }

20 Операция конкатенации Операция конкатенации должна поддерживать следующие формы записи: 1. String + String 2. String + "a C string" 3."a C string" + String 4."a C string" + "a C string" 5. String += String 6. String += "a C string"

21 Операция конкатенации Теперь мы поддерживаем первые четыре сценария использования. Однако компилятор не может вывести оператор +=, даже если в классе определены операции + и =. Нам нужна своя реализация этого оператора: String& operator+=(const String &s); После реализации оператора +=, оператор + можно реализовать через +=

22 Операция конкатенации String operator+ (const String &a, const String &b) { String temp(a); // Конструктор // копирования temp += b; return temp; }

23 Оператор индексирования Пользователи класса String хотели бы получать доступ к отдельным символам строки с помощью следующего синтаксиса: String name ("kenny"); String buffer ("qenny");... cout << name[0] << endl; // k name[0] = 'K';... buffer[0] = name[0]; // "Kenny"

24 Оператор индексирования Для этого нам надо определить оператор индексирования: char& String::operator[] (int index) { return data[index]; } Обратите внимание на использование ссылки.

25 Оператор индексирования Также хорошо бы иметь и вот такую версию этого оператора: const char& String::operator[] (int index) const { return data[index]; } Она будет вызываться для константных объектов класса String.

26 Перегрузка операторов В каких случаях оператор надо делать членом класса, а в каких глобальной функцией? –Если нужно, что бы левый аргумент был другого типа, то оператор должен быть глобальной функцией. Возможно, другом (friend). –Операторы =, [], (), -> могут быть только членами класса. –Если есть возможность, оператор должен быть определён вне класса, но при этом не быть другом и находится в том же пространстве имён (namespace), что и сам класс.

27 String class String { public: String(const char* s = NULL); // Конструктор String(const String& s); // Конструктор копирования ~String (); // Деструктор String& operator= (const String& s); // Присваивание String operator+ (const String& s); // Конкатенация char& operator[] (int element); // Оператор индексации friend ostream& operator<< (ostream& os, String& s); // Вывод в поток int length (void) const; // Длина operator const char*() const; // Преобразование типа private: char* data; };

28 Оператор вывода в поток Оператор вывода в поток обязательно должен быть глобальной функцией. Реализация часто очень проста: std::ostream& operator<< (std::ostream& os, String& s) { return (os << s.data); } В конце оператор обязательно должен возвращать ссылку на ostream для поддержки последовательного вывода: String s1, s2; std::cout << s1 << " " << s2; //operator<<(std::cout, s1).operator<<(" ")...

29 Преобразование типов Было бы хорошо, если бы наш класс можно было использовать следующим образом: String s; if (!strcmp(s, "Hello")) {... }

30 Преобразование типов Для этого нам нужно реализовать свой оператор преобразования к типу char *: operator const char*() const { return data; }

31 StrNum Немного отвлечемся от нашего класса String, и рассмотрим другой класс: class StrNum { public: StrNum(int num = 0); StrNum(const char *s); int GetValue() const; private: char value[12]; };

32 StrNum Мы уже умеем перегружать оператор сложения. Теперь перегрузим унарный минус. int operator-(const StrNum& strNum) { return –atoi(strNum.value); }

33 Префиксные и постфиксные операторы Перегрузим оператор инкремента (++). Он обязательно должен быть членом класса.

34 Префиксные и постфиксные операторы // Префиксный // оператор // Например, ++i int operator++() { int v = atoi(value); ++v; itoa(v, value); return v; } // Постфиксный // оператор // Например, i++ int operator++(int) { int old = atoi(value); itoa(old + 1, value); return old; }

35 Префиксные и постфиксные операторы В постфиксном инкременте второй int введён только для того, чтобы можно было различить постфиксный и префиксный операторы инкремента. int operator++(int) Аналогичным образом перегружаются префиксный и постфиксный операторы декремента (--).

36 Спасибо за внимание Вопросы?