Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
69
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

7.6.3. Конструктор копіювання

Конструктор копіювання є конструктором особливого типу: він приймає як параметр константне посилання на об'єкт класу (const тип_класу &) чи просте посилання на об'єкт (тип_класу &). Наприклад:

class Card

{int x,y;

public:

Card(const Card & src);};

Card::Card(const Card & src)

{x=src.x;

y=src.y;}

Розглянемо застосовність конструкторів копіювання. Напишемо програму:

#define LARGE 30000

struct Large

{int data[LARGE];

Large (void)

{for(int i=0;i<LARGE;i++)

data[i]=i;}

~Large(void){}

Large slow(Large b)

{Large ans;

{for(int i=0;i<LARGE;i++)

ans.data[i]=b.data[i];

return ans;}};

main()

{Large a,b;

{for(int i=0;i<100;i++)

a.slow(b);};

Час її роботи порівняно тривалий. Як збільшити швидкодію? Це можна зробити з використанням конструктора копіювання:

class Large1

{private:

Large1(const Large1 & b);

public:

Int data[large];

Large1(void)

{for(int i=0;i<LARGE;i++)

data[i]=i;}

~LARGE1(void){}

Large1 fast(const Large1 &);

};

Large1::Large1(const Large1 & b);

{for(int i=0;i<LARGE;i++)

data[i]=b.data[i];}

Inline Large1 Large1::fast(const Large1 & b)

{return Large1(b);}

main()

{Large1 a,b;

for(int i=0;i<100;i++)

a.fast(b);};

Ця версія програми, що використовує конструктор копіювання, працює значно швидше, адже за рахунок конструктора копіювання не створюються локальні копії структур. Конструктор у закритій частині опису класу використовується для прискорення оператора return у fast. Це можна пояснити тим, що дані, розміщені в закритому розділі класу, у даному випадку містяться в одному сегменті, і доступ до них здійснюється з використанням near-адресації, тобто одного лише зміщення.

7.7. Глобальні та локальні об'єкти

Підсумуємо інформацію про локальні та глобальні об'єкти, яка тією чи іншою мірою вже зустрічалась вище.

Глобальні об'єкти. Конструктори глобальних об'єктів викликаються до початку виконання функції main() у порядку їх наступності. Це забезпечує ініціалізацію всіх глобальних об'єктів класу до формального початку виконання програми – виклику функції main(). Деструктори глобальних об'єктів класу викликаються як частини коду завершення програми, після відпрацювання всіх функцій завершення, заданих викликом функції atexit(). Деструктори не викликаються, якщо програма завершується за допомогою функції abort().

Локальні об'єкти. Автоматичні об'єкти класу, оголошені локальними у функції, створюються разом з викликом функції та знищуються разом із завершенням її роботи. Автоматичні об'єкти зберігаються в стеку, як і звичайні автоматичні змінні. При завершенні роботи функції викликаються деструктори локальних об'єктів. Якщо програма завершується за допомогою виклику функції exit(), то деструктори глобальних об'єктів викликаються як завжди, а локальних – не викликаються. Наприклад:

class empty{

public:

char*obj_name;

empty(char*name)

{cout<<"створений об’єкт з ім’ям"<<name<<"класу empty\n";

obj_name=name;}

~empty()

{cout<<"об’єкт з ім’ям"<<obj_name<<"знищений\n";}

} one("one");

Void main(void)

{empty second("second");}

Результати роботи програми:

створений об’єкт з ім’ям one класу empty

створений об’єкт з ім’ям second класу empty

об’єкт з ім’ям second знищений

об’єкт з ім’ям one знищений

Покажчики на об'єкти. Покажчики можуть посилатися на динамічні об'єкти, пам'ять для яких виділяється за допомогою операції new:

Timer*ptoday;

ptoday=new Timer;

У купі виділяється область для об'єкта типу Timer. Адреса першого байта цієї області присвоюється ptoday. Крім того, С++ викликає конструктор за умовчанням, який ініціалізує об'єкт. Якщо необхідно виділити пам'ять і викликати інший конструктор, то можна вказати відповідні параметри:

ptoday=new Timer(9,14,1917,10,45).

Об'єкти-посилання. Об'єкти можуть оголошуватись як посилання. Наприклад, оголошено глобальний об'єкт

Timer today;

Можемо визначити посилання:

Timer & rtoday=today;

Rtoday – це посилання. Оскільки посилання здійснюється на вже існуючі об'єкти, то при вході в область дії посилання конструктор класу не викликається і, відповідно, не викликається деструктор при виході з області дії.

Об'єкти – результати функцій. Об'єкти, посилання й покажчики на них можуть виступати як аргументи функцій. Функція може повертати об'єкт безпосередньо:

Timer newtime(void)

{Timer t;

return t;}

Тоді функція може викликатися так:

Timer anothertime=newtime();

При цьому результат, який повертається функцією newtime(), копіюється в anothertime. Однак у нашому випадку це не логічно, адже аналогічні дії виконуються при оголошенні: Timer anothertime;

Часто використовують посилання на об'єкт чи покажчик на об'єкт як результат функції:

Timer*newtime(void)

{Timer*p=new Timer;

return p;}

Тоді можна використати newtime() для отримання нового обє'кта та присвоїти його адресу покажчику на Timer:

Timer*tp=newtime();

Функції-посилання можна використовувати для посилання на існуючі об'єкти:

Timer today; – глобальний об'єкт.

Timer &newtimer(void)

{return today;}

Можна оголосити посилання на today:

Timer & tr=newtimer();

Масиви об'єктів. Масив об'єктів синтаксично задається як звичайний масив:

Timer tentimes[10];

При цьому клас, екземпляри якого утворюють масив, повинен обов'язково мати конструктор за умовчанням. Розглянемо приклад роботи з масивами об'єктів:

main(void)

{ Timer tentimes[10];

for(int i=0;i<10;i++) tentimes[i].display();

return 0;}

Очевидно, що тут буде надруковано 10 однакових значень.

Можна ініціалізувати масив так:

main(void)

{Timer tarray[3]={Timer(),Timer(8),Timer(8,1)};

for(int i=0;i<3;i++)tarray[i].display();

return 0;}

Масиви об'єктів можуть розміщуватись у купі та адресуватись за допомогою покажчиків:

main()

{Timer*tarrayp;

tarrayp=new Timer[6];

for(int i=0;i<6;i++)

tarrayp[i].display();

delete[ ]tarrayp;

return 0;}

У цьому прикладі шість разів викликається конструктор за умовчанням при виділенні пам'яті оператором new та шість разів – деструктор при звертанні до delete, яка вжита в специфічній формі – із квадратними дужками (C++ ігнорує будь-які значення всередині дужок).