Лекция 12 Перегрузка операторов. Часть 2. Подбельский гл. 9.7, Страуструп гл. 11, Мейрс п. 11,15-17,19. Перегрузка копирующего конструктора T(const T&)

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



Advertisements
Похожие презентации
Лекция 13 Производные классы и открытое наследование. Подбельский гл , Страуструп гл , Мейрс пп Открытое наследование производного.
Advertisements

Лекция 10 Класс как абстрактный тип. Подбельский гл. 9, Страуструп гл. Конструкторы и деструктор Конструкторы - это специальные функции-члены класса, предназначенные.
Лекция 13. Введение в ООП. Часть 4 Красс Александр СПбГУ ИТМО, 2008.
Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
1 Переопределение операций Макаревич Л. Г.. 2 Зачем нужна перегрузка операций? class Complex { double re; double im; public: Complex(double r=0, double.
Лекция 8. Введение в ООП. Часть 1 Красс Александр СПбГУ ИТМО, 2008.
Практическое занятие 6. Функции. Большинство языков программирования используют понятия функции и процедуры. C++ формально не поддерживает понятие процедуры,
Статические поля класса Статические поля хранят данные, общие для всех элементов класса. Статическое поле существует в единственном экземпляре для всех.
Синтаксис языка Java. Символы и синтаксис Перевод строчки эквивалентен пробелу Регистр в именах различается.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Лекция 10 ОбъектыЛекция 10 ОбъектыООП Инкапсуляция Возможность совместного хранения данных и кода для их обработки Наследование Возможность расширять существующие.
Конструкторы и Деструкторы Конструкторы - функции, явно предназначенные для инициализации объектов Деструкторы - функция обратная конструктору для обеспечения.
ООП Классы – 2.
Лекция 10. Введение в ООП. Часть 3 Красс Александр СПбГУ ИТМО, 2008.
Потоки Язык C++ не обеспечивает средств для ввода/вывода Ему это и не нужно; такие средства легко и элегантно можно создать с помощью самого языка Традиционно.
Работа с файлами Сазонов Д.О. ПМиЭММ Часть 2. Тема занятия: Работа с файлами через потоки Для реализации файлового ввода/вывода, необходимо включить в.
Дружественные функции Дружественные функции – это функции, объявленные вне класса, но имеющие доступ к закрытым и защищенным полям данного класса Дружественная.
Наследование Полиморфизм ВЫЗОВ КОНСТРУКТОРОВ И ДЕСТРУКТОРОВ ПРИ НАСЛЕДОВАНИИ.
Инструкции C++ Условная инструкция Формат: if (условие) оператор; else оператор; Пример: if (i!=0) { if (j) j++; if(k) k++; else if(p) k--; } else i--;
Прикладное программирование кафедра прикладной и компьютерной оптики Полиморфизм.
Транксрипт:

Лекция 12 Перегрузка операторов. Часть 2. Подбельский гл. 9.7, Страуструп гл. 11, Мейрс п. 11,15-17,19. Перегрузка копирующего конструктора T(const T&) и оператора присваивания operator= А зачем все это нужно? Если Вы этого не сделаете, то компилятор сам сгенерирует о.ф. operator=, которая будет выполнять почленное присваивание членов-данных одного объекта соответствующим членам другого. Для указателей такое присваивание означает побитовое копирование. Чем это грозит Вам в том случае, если для класса определены конструктор(-ы) с динамическим выделением памяти и деструктор с удалением этой памяти? len==4 sz==5 nameGame\0 len==5 sz==6 nameover\0! { Tbl t1("Game"), t2("over!"); t1t2

t2=t1; len==4 sz==5 nameGame\0 len==4 sz==5 name over\0! t1t2 На этот кусок памяти теперь ничто не указывает - это мусор! Tbl t3=t1; // эквивалентно Tbl t3(t1); // произойдет вызов копирующего конструктора Tbl(const Tbl&); Если Вы этого не сделаете, то компилятор языка С++ сам сгенерирует функцию конструктора Tbl(const Tbl&), которая будет выполнять почленное присваивание членов-данных объекта- образца соответствующим членам нового объекта. Для указателей такое присваивание означает побитовое копирование. len==4 sz==5 name t3 } // Конец блока (функции). Удаление локальных объектов t1, t2, t3 путем //вызова ~Tbl() деструктора для каждого из них. Трижды будет выполнена попытка // удалить с помощью delete[] из динамической памяти строку "Game", // что приведет к фатальной ошибке.

class Tbl { public:... Tbl(const Tbl&); // объявление копирующего к-ра в открытой части класса Tbl& operator= (const Tbl&); // объявление о.ф. в открытой части класса ~Tbl(){delete[] name;}//определение деструктора, удаляющего строку из дин. памяти private:... char *name; int sz, len; }; Tbl::Tbl(const Tbl& t) { len = t.len; name = new char [sz=t.sz]; // создаем новую строку в дин. памяти strcpy(name,t.name); // strcpy объявлена в } Tbl& Tbl::operator=(const Tbl& orig) { if (&orig != this) { // проверка на присваивание самому себе delete [] this->name; // удаляем старую строку this->name = new char [sz=orig.sz]; // создаем новую memcpy(this->name,orig.name,orig.sz); // копируем оригинал в новую строку len = strlen(name); // memcpy и strlen объявлены в } return *this; // возвращаем (ссылку на) объект, для которого была вызваны о.ф. } Пример 12.1: Перегрузка копирующего конструктора T(const T&) и оператора присваивания operator=

Как все это работает? len==4 sz==5 nameGame\0 len==5 sz==6 name over\0! { Tbl t1("Game"), t2("over!"); // сначала все также t1t2 t2=t1; // произойдет вызов перегруженного operator= len==4 sz==5 nameGame\0 len==4 sz==5 name over\0! t1t2 Удаляется в operator=() с помощью delete [] Tbl t3=t1; // эквивалентно Tbl t3(t1); произойдет вызов определенного Вами // копирующего конструктора Tbl(const Tbl&); len==4 sz==5 name t3 Game\0 Game } // Конец блока (функции). Удаление локальных объектов t1, t2, t3 путем //вызова деструктора ~Tbl()для каждого из них. Трижды будет выполнена попытка // удалить с помощью delete[] из динамической памяти строку "Game", // Но каждый раз будут удаляться разные объекты.Что и требовалось добиться.

Вопросы для самостоятельного изучения: Почему в качестве типа возвращаемого значения operator= плохо использовать void ? Почему тип возвращаемого значения operator=() Tbl &, а не const Tbl& ? Почему operator=() возвращает ссылку на объект, стоящий слева от =, а не справа ? Перегрузка операторов >> и << Придадим оператору > смысл извлечения данных-членов объектов класса Tbl из потока ввода. Чтобы сохранить естественный синтаксис операторов >> и << необходимо, чтобы объект класса Tbl являлся правым операндом. По этой причине мы обязаны в обоих случаях использовать внешнюю функцию (не член класса). Доступ к закрытым данным мы предоставим этим о.ф., объявив их друзьями класса (но можно иначе). Пример 12.2: Перегрузка оператора >> для извлечения данных-членов объектов класса Tbl из потока ввода. Для извлечения строки символов из потока ввода, воспользуемся getline() функцией-членом класса istream. Определение классов istream и ostream находятся в файле. #include class Tbl {... friend istream& operator>>(istream&, Tbl& ); // прототип друга может быть помещен friend ostream& operator>>(ostream&, const Tbl&); // в любой части класса... };

istream& operator>>(istream& in, Tbl& t) { delete [] t.name; t.name = new char [t.sz=81]; in.getline(t.name,81); t.len=strlen(t.name); } ostream& operator << (ostream& out, const Tbl& t) { out.width(2); out<<dec<<" SZ=="<<t.sz <<" LEN=="<<t.len <<" NAME=\""<<t.name<<"\" ptr=="<<hex<<int(t.name); } Определения операторных функций >> и << вне класса. Использование >> и << int main() { Tbl t1("Time"),t2(8),t3; cout<<t1<<endl<<t2<<endl<<t3<<endl; Tbl t4=t1; // эквивалентно Tbl t4(t1); произойдет вызов определенного Вами cout<<t4<<endl; // копирующего конструктора Tbl(const Tbl&); t3=" "; // сначала будет вызван Tbl(const char* ), а потом operator=() // после этого деструктор ~Tbl() cout<<t3<<endl; cout<<"Enter string:"<<endl; cin>>t2; cout<<t2<<endl; } // деструктор ~Tbl() будет вызван еще 4 раза

Будет напечатано: SZ==5 LEN==4 NAME="Time" ptr==22550 SZ==8 LEN==0 NAME="" ptr==22560 SZ==32 LEN==0 NAME="" ptr==22958 SZ==5 LEN==4 NAME="Time" ptr==22570 delete sz==9 len==8 SZ==9 LEN==8 NAME=" " ptr==23378 Enter string: qwerty SZ==81 LEN==6 NAME="qwerty" ptr==23960 delete sz==5 len==4 delete sz==9 len==8 delete sz==81 len==6 delete sz==5 len==4