cpp-oop (823968), страница 16
Текст из файла (страница 16)
Поэтому как для определенных пользователемтипов полей классов, так и для классов целиком при выводе объектов этих классовоперации «<<» и «>>» следует переопределять для каждого класса.ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»118При переопределении операций «включение в поток» и «извлечение из потока»используется следующая форма описания операций:osrteam & operator<<(ostream & out,<Новый тип> <Имя>)<Тело функции-оператора> }{istream & operator >>(istream & in,<Новый тип> &<Имя>)<Тело функции-оператора> }{Причем при вовлечении в эти операции полей, описанных private и protected,операции «<<» и «>>» приходится описывать как дружественные.Пример 5.3.
Переопределение операций ввода-вывода (класс Целое число).#include <locale.h>#include <stdio.h>#include <stdlib.h>#include <iostream>using namespace std;typedef unsigned long dlong;class Tlong{public:dlongnum;Tlong(){}Tlong(dlong an) { setnum(an);}friend ostream & operator <<(ostream &out,Tlong obj);friend istream & operator >>(istream & in,Tlong &obj);void print(void);void setnum(dlong an) { num=an;}};ostream & operator <<(ostream & out,Tlong obj){out<<" Значение числа :"<<obj.num<<endl;return out;}istream & operator >>(istream & in,Tlong &obj)ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»119{cout<<" Введитечисло"<<endl;in>>obj.num;return in;}void Tlong::print(){cout<<" значениечисла : "<<num<<endl; }void main(){setlocale(0,"russian");Tlong a,b;cout<<"Ввод значений полей объектов"<<endl;cin>>a>>b;cout<<"ПРОСТОЙ ОБЪЕКТcout<<"ПРОСТОЙ ОБЪЕКТa"<<a<<endl;b"<<b<<endl;system("pause");}ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»120Особенности переопределении операции присваивания5.4Операция присваивания по умолчанию определена для любого класса иобеспечивает копирование полей объектов, аналогичное тому, которое выполняется поумолчанию в копирующем конструкторе. При необходимости эту операцию также можнопереопределить, однако выполнение операции присваивания имеет свои особенности,которые следует учитывать.Пример5.4.Конструированиеиуничтожениевременныхобъектовприпереопределении операции присваивания.Чтобы отследить процессы конструирования и уничтожения объектов в том числевременных,переопределимтакжекопирующийконструкторидеструктор.Непосредственной необходимости в их переопределении не существует, но ихпереопределение позволит уточнить последовательность выполняемых операций.#include <iostream>using namespace std;class TP{private:float x,y;public:TP(float ax,float ay):x(ax),y(ay){cout<<"Constructor\n";}TP(){cout<<"Constructor without parameters\n";}TP(TP &p){cout<<"Copy\n";x=p.x; y=p.y;}~TP(){cout<<"Destructor\n";}void Out(void){cout<<"\n{"<<x<<","<<y<<"}\n"; }// a+=bTP& operator+=(TP &p){x+=p.x; y+=p.y;cout<<"operator+=\n";return *this;ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»121}// a+bTP operator+(TP &p){TP pp(x,y);cout<<"operator+\n";return pp+=p;}TP& operator=(TP &p)// a=b{x=p.x; y=p.y;cout<<"operator=\n";return *this;}};void main(){TP p(2,3),q(4,5),r(7,8);p+=r;p.Out();q=p+r;q.Out();system("pause");}Полученныйрезультат–трассу конструирования/уничтоженияобъектов ивыполнения функций операторов сопоставим текстам программ (см. табл. 5.3).При выполнении операции сложения создается новый объект.
Этот объект, являясьавтоматическим, уничтожается в момент завершения работы функции. Но он содержитрезультат. Анализ трассы показывает, что для передачи результата в основную программукомпилятор С++ создает внутренний временный объект – копию результата. Эта копияпередается функции, реализующей операцию присваивания, а затем – автоматическиуничтожается.ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»122Таблица 5.3. Последовательность конструирования и уничтожения объектов привыполнении операций сложения и операции присваиванияОперацияp+=r;Текст функции 1TP&Текст функции 2Вывод–operator+=(TP &p){x+=p.x; y+=p.y;Operator +=cout<<"+=\n";return *this;}q=p+r;TP operator+(TP &p){TP pp(x,y);Constructorcout<<"operator+\n";Оperator +pp+=p;TP& operator+=(TP &p){x+=p.x; y+=p.y;cout<<"+=\n";Operator +=return *this;Copy}Destructor}TP& operator=(TP &p){x=p.x; y=p.y;Operator =cout<<"operator=\n";return *this;Destructor}Операции создания объекта копии и его уничтожения в таблице выделеныполужирным шрифтом.ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»1235.5Переопределение операций для объектов с динамическими полями. Контрольосвобождения динамической памятиОсобо аккуратно следует переопределять операции для объектов с динамическимиполями, поскольку при этом велика вероятность допустить «утечку памяти». В разделе 1.4указано, что класс, описывающий объекты с динамическими полями, должен включатькопирующий конструктор. По тем же причинам он должен переопределять операциюприсваивания.Пример 5.5.
Переопределение операций для объектов с динамическими полями.#include <string.h>#include <stdio.h>#include <iostream>using namespace std;class String{private:public:char *str,name;intlen;String(int Len,char Name); // пустая строка с памятьюString(char *vs,char Name);// инициализированная строкаString(String &S);// копия строки~String();// освободжение памятиint Length(){return len;}// определение длиныchar operator[](int n)// чтение символа из строки{return ((n>=0)&&(n<len))?str[n]:'\0';}// вывод строки и ее длиныvoid print(){cout<<"Str: "<<name<<":";cout<<str<<" Length: "<<len<<endl;}Stringoperator+(String &A);// слияние строкStringoperator+(char c);// добавление символаString& operator=(String &S);// присваивание строкОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»124};String::String(int Len,char Name){len=Len; str=new char[len+1];str[0]='\0'; name=Name;cout<<"Constructor length "<<name<<"\n";}String::String(char *vs,char Name){len=strlen(vs); str=new char[len+1];strcpy(str,vs);name=Name;cout<<"Constructor "<<name<<"\n";}String::String(String &S){len=S.Length(); str=new char[len+1];strcpy(str,S.str); name='K';cout<<"Copy from "<<S.name<<" to "<<name<<"\n";}String::~String(){delete [] str;cout<<"Destructor "<<name<<"\n";}StringString::operator+(String &A){cout<<"Operation +"<<"\n";int j=len+A.Length();String S(j,'S');strcpy(S.str,str);strcat(S.str,A.str);cout<<"Operation +"<<"\n";return S;}StringString::operator+(char c){cout<<"Operation +c"<<"\n";String S(j,'Q');int j=len+1;strcpy(S.str,str);ОглавлениеИванова Г.С., Ничушкина Т.Н.
«Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»125S.str[len]=c;S.str[len+1]='\0';cout<<"Operation +c"<<"\n";return S;}String& String::operator=(String &S){cout<<"Operation ="<<"\n";len=S.Length();if (str!=NULL) delete[]str;str=new char[len+1];strcpy(str,S.str);cout<<"Operation ="<<"\n";return *this;}void main(){String A("ABC",'A'),B("DEF",'B'),C(6,'C');C.print();C=A+B;C.print();C=C+'a';C.print();system("pause");}Проанализируем трассу выполнения операции сложения (см. табл. 5.4).ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»126Таблица 5.4.
Результат выполнения операции сцепления строкОперацияC=A+B;Выполняемые операторыРезультатыString operator+(String &A){ cout<<"Operation +"<<"\n";Operation +int j=len+A.Length();String S(j,'S');Constructor length Sstrcpy(S.str,str);strcat(S.str,A.str);cout<<"Operation +"<<"\n";Operation +return S;Copy from S to K}Destructor SString& operator=(String &S){cout<<"Operation =" <<"\n";Operation =len=S.Length();if (str!=NULL) delete[]str;str=new char[len+1];strcpy(str,S.str);cout<<"Operation ="<<"\n";Operation =return *this;Destructor K}Аналогично предыдущему примеру передача результата операции присваиванияосуществляется через временный объект – копию переменной, хранящей результирующеезначение.ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»127Вопросы для самоконтроля1.
Что такое переопределение операций?Ответ.2. Какие операции можно переопределять?Ответ.3. Чем отличаются компонентные и внешние функции-операторы?Ответ.ОглавлениеИванова Г.С., Ничушкина Т.Н. «Объектно-ориентированное программирование на языке C++ в среде Microsoft Visual Studio 2008»12866.1ШаблоныПараметризованные функцииШаблон функции – это глобальная функция, определенная за пределами классов. Вотличие от перегрузки функции, при которой для каждой сигнатуры создается свояфункция, шаблон семейства функций определяется один раз, но это описание содержитпараметры. Для задания параметров используется список:template <Список параметров шаблона> <Описание функции>Каждый формальный параметр шаблона обозначается ключевым словом class, закоторым следует имя параметра.