Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

техпрог / Comp-Sci-05

.pdf
Скачиваний:
44
Добавлен:
10.02.2015
Размер:
845.74 Кб
Скачать

Материалы к лекции 5.

Объектно-ориентированное программирование

Конструктор копирования

Имеется подставляемый системой конструктор копирования, он не игнорируется даже, если в классе уже определены конструкторы. Причѐм, не важно, есть у класса конструкторы по умолчанию или нет.

Пример.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-2";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;} int get_speed(){return speed;} void set_year(int y){year=y;} int get_year(){return year;}

};

int main()

{Cdrom acer(48,2007); acer.set_speed(50); acer.set_year(2008);

Cdrom lg=acer;//инициализация с помощью существующего объекта cout<<"\nCd-Rom Acer "<<acer.get_speed()<<acer.get_year(); cout<<"\nCd-Rom LG "<<lg.get_speed()<<lg.get_year()<<endl;

cout<<"&acer= "<<&acer<<" &lg= "<<&lg; return 0;

}

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

Пример.

#include <iostream> using namespace std; class Cdrom{

int speed;//скорость int year;// год выпуска

public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";}

~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed(){return speed;}

void set_year(int y){year=y;}

int get_year(){return year;}

};

int main()

{Cdrom acer;

acer.set_speed(48); acer.set_year(2007);

Cdrom lg=acer;//инициализация с помощью существующего объекта Cdrom sony(acer); //другая форма вызова конструктора копирования cout<<"\nCd-Rom LG "<<lg.get_speed()<<lg.get_year(); cout<<"\nCd-Rom Sony "<<sony.get_speed()<<sony.get_year()<<endl; cout<<"&acer= "<<&acer<<" &lg= "<<&lg<<" sony= "<<&sony;

return 0;

}

Замечание. Синтаксис инициализации и конструктора копирования в C++ распространен на встроенные типы, хотя, в данном случае конструкторы не вызываются.

#include <iostream> using namespace std; int main()

{int x(100); //x=100 int y(x); //y=x

cout<<"x= "<<x<<"y= "<<y<<endl;

cout<<"&x= "<<&x<<" &y= "<<&y;//адреса разные! int z(200+x*y);

cout<<"\nz= "<<z<<endl; return 0;

}

Конструктор преобразования

Конструктор преобразования – это конструктор с одним параметром какого-то другого типа (не как у атрибутов класса).

Пример.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";}

Cdrom(double x){speed=(int)x;year=2004;}//конструктор преобразования

~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed(){return speed;} void set_year(int y){year=y;} int get_year(){return year;}

};

int main()

{Cdrom acer(52,2004);

Cdrom nec=31.2;

cout<<"\nCd-Rom NEC "<<nec.get_speed()<<nec.get_year(); return 0;

}

Пример. Конструктор преобразования. Объект acer создаѐтся конструктором Constr-1, объект Sony создаѐтся конструктором преобразования Constr-2.

#include <iostream>

using

namespace std;

class

Cdrom{

 

int speed; int year; char marka[20];

public:

Cdrom(int s,char *m, int y=2002) {speed=s; strcpy(marka,m); year=y; cout<<"\nConstr-1";}

Cdrom (char *x) {speed=40; year=2004; strcpy(marka,x); cout<<"\nConstr-2";}

~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed(){return speed;}

void set_year(int y){year=y;}

int get_year(){return year;}

};

 

int main()

 

{

Cdrom acer(52,"Acer++",2008); Cdrom sony("Sony");

cout<<"\nCd-Rom sony "<<sony.get_speed()<<'\t'<<sony.get_year()<<endl; return 0;

}

Пример. Объявление Cdrom maxi=acer.Sravnim(nec); приведѐт к вызову метода Sravnim(), а затем конструктора копирования Constr-3. Объекты acer и maxi имеют разные адреса.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";}

Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed(){return speed;}

void set_year(int y){year=y;}

int get_year(){return year;}

Cdrom Sravnim(Cdrom &p){cout<<"Sravnim()";

if (speed<p.speed) return p;

else return *this; }//можно было бы с помощью оператора ?

};

 

int main()

 

{

 

Cdrom acer(52,2008);

Cdrom nec(32,2001);

Cdrom maxi=acer.Sravnim(nec);

cout<<"\nCd-Rom maxi "<<maxi.get_speed()<<'\t'<<maxi.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &maxi= "<<&maxi;

return 0;

}

Замечание. Могли бы использовать заголовок Cdrom Sravnim(const Cdrom &p), т. к. аргумент функции не изменяется. Отметим, что функция возвращает копию объекта.

Пример. Возвращаем объект с помощью указателя. Адреса у объектов maxi и acer одинаковые. Конструктор копирования не вызывается.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed(){return speed;} void set_year(int y){year=y;} int get_year(){return year;}

Cdrom * Sravnivaem(Cdrom &p){return (speed<p.speed) ? &p : this;}

};

int main()

{

Cdrom acer(52,2008); Cdrom nec(32,2001);

Cdrom * maxi=acer.Sravnivaem(nec);

cout<<"\nCd-Rom maxi "<<maxi->get_speed()<<'\t'<<maxi->get_year(); cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" maxi= "<<maxi;

// у maxi и acer адреса одинаковые! return 0;

}

Замечание. Если изменить заголовок функции Sravnivaem() на

Cdrom * Sravnivaem(const Cdrom &p)

то при вызове

Cdrom * maxi=acer.Sravnivaem(nec);

получим сообщение об ошибке, хотя параметр–объект и не изменяется функцией. Компилятор не может выполнить преобразование из 'const class Cdrom *' в 'class Cdrom *', поскольку функция имеет возвращаемое значение Cdrom *. Необходимо преобразование типов, которое можно выполнить с помощью const_cast (аннулирует действие модификатора const, т. е. указатель на постоянный объект преобразуется в указатель на непостоянный объект). Можем исправить функцию Sravnivaem() следующим образом:

Cdrom * Sravnivaem(const Cdrom &p)

{return (speed<p.speed) ? const_cast<Cdrom *>(&p) : this;}

или

Cdrom * Sravnivaem(const Cdrom &p)

{return (speed<p.speed) ? (Cdrom *)(&p) : this;}

Пример. Возвращаем объект с помощью ссылки. Адреса у объектов maxi и acer одинаковые. Конструктор копирования не вызывается.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";}

~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;} int get_speed()const{return speed;} void set_year(int y){year=y;} int get_year()const{return year;}

Cdrom & Sravnenie(Cdrom &p) {return (speed<p.speed) ? p : *this; }

};

int main()

{

Cdrom

acer(52,2008);

Cdrom nec(42,2005);

Cdrom

& maxi=acer.Sravnenie(nec);

cout<<"\nCd-Rom maxi "<<maxi.get_speed()<<'\t'<<maxi.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &maxi= "<<&maxi;

return 0;

}

Если заменить

Cdrom & maxi=acer.Sravnenie(nec);

на

Cdrom maxi=acer.Sravnenie(nec);

то будет вызван конструктор копирования и адреса у объектов maxi и acer будут уже разными.

Пример. Изменим заголовок функции Sravnenie(), добавив const.

const Cdrom & Sravnenie(const Cdrom &p) const

{return (speed<p.speed) ? p : *this; }

Ключевое слово const у параметра функции указывает, что функция не вносит изменений в объект, переданный как параметр (в примере это nec). Поскольку функция возвращает ссылку на один из объектов (вызвавший функцию или переданный через параметр), const нужно поставить и в возвращаемый тип – иначе будет сообщение об ошибке. Ключевое слово в конце заголовка означает, что не изменяется объект, вызвавший функцию (в примере это acer).

Отметим, что в этом примере, при создании объекта maxi будет вызван конструктор копирования, адреса у maxi и acer разные.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s;year=y;cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}int get_speed()const{return speed;} void set_year(int y){year=y;} int get_year()const{return year;} const Cdrom & Sravnenie(const Cdrom &p) const

{return (speed<p.speed) ? p : *this; }

};

 

int main()

 

{

 

Cdrom acer(52,2008);

Cdrom nec(32,2001);

Cdrom maxi=acer.Sravnenie(nec);

cout<<"\nCd-Rom maxi "<<maxi.get_speed()<<'\t'<<maxi.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &maxi= "<<&maxi;

return 0;

}

Использовать ссылку как в более раннем примере не удастся. С помощью приведения типов можно исправить ситуацию, но адреса у объектов будут различными (так как будет создаваться ещѐ один объект):

Cdrom &maxi=(Cdrom)acer.Sravnenie(nec);

или, что то же самое, но с явным указанием того, что вызывается конструктор

Cdrom &maxi=Cdrom(acer.Sravnenie(nec));

Пример. Строка acer.Sravnenie(nec)=sony; вызовет конструктор копирования, адреса у трех участвующих в операции объектов будут разными. Какой объект (acer или nec) получит значения объекта sony зависит от того, что вернѐт функция

Sravnenie().

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s; year=y; cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}

int get_speed()const{return speed;}

void set_year(int y){year=y;}

int get_year()const{return year;}

Cdrom & Sravnenie(Cdrom &p){return (speed<p.speed) ? p : *this; }

};

 

int main()

 

{

 

Cdrom acer(52,2004);

Cdrom nec(32,2001);

Cdrom & maxi=acer.Sravnenie(nec);

cout<<"\nCd-Rom maxi "<<maxi.get_speed()<<'\t'<<maxi.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &maxi= "<<&maxi;

Cdrom sony(24,1998); acer.Sravnenie(nec)=sony;

cout<<"\nCd-Rom acer "<<acer.get_speed()<<'\t'<<acer.get_year()<<endl; cout<<"\nCd-Rom nec "<<nec.get_speed()<<'\t'<<nec.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &sony= "<<&sony;

return 0;

}

Замечание. Если же записать const, то оператор acer.Sravnenie(nec)=sony; приведѐт к ошибке.

#include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s; year=y; cout<<"\nConstr-1";}

Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;}

int get_speed()const{return speed;} void set_year(int y){year=y;}

int get_year()const{return year;}

const Cdrom & Sravnenie(const Cdrom &p) const

{return (speed<p.speed) ? p : *this; }

};

 

int main()

 

{ Cdrom acer(52,2004);

Cdrom nec(32,2001);

Cdrom maxi=acer.Sravnenie(nec);

cout<<"\nCd-Rom maxi "<<maxi.get_speed()<<'\t'<<maxi.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &maxi= "<<&maxi;

Cdrom sony(24,1998); acer.Sravnenie(nec)=sony; // теперь ОШИБКА

cout<<"\nCd-Rom acer "<<acer.get_speed()<<'\t'<<acer.get_year()<<endl; cout<<"\nCd-Rom nec "<<nec.get_speed()<<'\t'<<nec.get_year()<<endl; cout<<"&acer= "<<&acer<<" &nec= "<<&nec<<" &sony= "<<&sony;

return 0;

}

Пример вспомогательный. Максимальный элемент массива.

// Maxelemmass.cpp:

//

#include "stdafx.h" #include <iostream> using namespace std;

int _tmain(int argc, _TCHAR* argv[])

{

const int n=10;

int x[n]={1,23,3,45,5,6,7,8,9,10}; int i;

printf("\n");

for (i=0;i<n;i++) printf(" %d ",x[i]);

//

for (int mx=x[0],i=1;i<n;i++) mx=(mx<x[i])?x[i]:mx; printf("\n Max object %d \n",mx);

return 0;

}

Пример. Находим максимальный (в каком-то смысле) объект – в данном примере объект класса Cdrom с наибольшим значением speed.

// maxobject.cpp : #include "stdafx.h" #include <iostream> using namespace std; class Cdrom{

int speed; int year; public:

Cdrom(int s,int y=2002){speed=s; year=y; cout<<"\nConstr-1";} Cdrom(){speed=32;year=1999;cout<<"\nConstr-2";}

Cdrom(const Cdrom & c){speed=c.speed;year=c.year;cout<<"\nConstr-3";} ~Cdrom(){cout<<"\nDestructor";}

void set_speed(int s){speed=s;} int get_speed()const {return speed;}

void set_year(int y){year=y;}

int get_year()const{return year;}

const Cdrom & Sravnenie(const Cdrom &p) const {return (speed<p.speed) ? p : *this; }

};

int _tmain(int argc, _TCHAR* argv[])

{

const int n=10;

Cdrom x[n]={Cdrom(52,2005),Cdrom(42,2004),Cdrom(54,2005), Cdrom(40,2003),Cdrom(58,2007),Cdrom(52,2004),Cdrom(62,2008), Cdrom(20,2002),Cdrom(16,2000),Cdrom(12,1999)};

int i;

Cdrom mx=x[0]; printf("\n");

for (i=0;i<n;i++) printf(" %d ",x[i].get_speed());

//

for (i=1;i<n;i++) mx=mx.Sravnenie(x[i]); printf("\n Max object %d \n",mx.get_speed());

return 0;

}

Соседние файлы в папке техпрог