Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Namespace CounterNameSpace 5 страница




 

getch (); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

Базовий клас.

Перший похідний клас.

Другий похідний клас.

Тепер розглянемо код цієї програми детально, щоб зрозуміти, як вона працює.

У класі baseClass функція who() оголошена віртуальною. Це означає, що її можна перевизначити у похідному класі (у класі, виведеному з baseClass). І вона дійсно перевизначається в обох похідних класах firstD і secondD. У функції main () оголошуються чотири змінні: Base_ob (об'єкт типу baseClass), p (покажчик на об'єкт класу baseClass), а також два об'єкти First_ob і Second_ob двох похідних класів firstD і secondD відповідно. Потім покажчику р присвоюється адреса об'єкта Base_ob і викликається функція who(). Оскільки функцію who() оголошено віртуальною, то мова C++ у процесі виконання програми визначає, до якої саме версії функції who() тут потрібно звернутися, причому рішення приймається шляхом аналізу типу об'єкта, яка адресується покажчиком р. У цьому випадку р вказує на об'єкт типу baseClass, тому спочатку виконується та версія функції who(), яку оголошено у класі baseClass. Потім покажчику р присвоюється адреса об'єкта First_ob. Пригадайте, що за допомогою покажчика на базовий клас можна звертатися до об'єкта будь-якого його похідного класу. Тому, коли функція who() викликається удруге, мова C++ знову з'ясовує тип об'єкта, який адресує покажчик р, і, виходячи з цього типу, визначає, яку версію функції who() потрібно викликати. Оскільки р тут вказує на об'єкт типу firstD, то виконується версія функції who(), визначену у класі firstD. Аналогічно після присвоєння покажчику р адреси об'єкта Second_ob викликається версія функції who(), оголошена у класі secondD.

Необхідно пам'ятати! Те, яка версія віртуальної функції дійсно буде викликана, визначається у процесі виконання програми. Рішення ґрунтується виключно на аналізі типу об'єкта, яка адресується покажчиком на базовий клас.

Віртуальну функцію можна викликати звичайним способом (не через покажчик), використовуючи оператор "крапка" і задаючи ім'я об'єкта, що викликається. Це означає, що у попередньому прикладі було б синтаксично коректно звернутися до функції who() за допомогою такої настанови:

First_ob.who();

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

Якщо віртуальна функція перевизначається у похідному класі, то її називають перевизначеною.

Спочатку може видатися, що перевизначення віртуальної функції у похідному класі є спеціальною формою перевантаження функцій. Але це не так. Насправді ми маємо справу з двома принципово різними процесами. Передусім, версії перевантаженої функції повинні відрізнятися одна від іншої типом і/або кількістю параметрів, тоді як тип і кількість параметрів у версіях віртуальної функції повинні точно збігатися. І справді, прототипи віртуальної функції та її перевизначення мають бути абсолютно однаковими. Якщо прототипи будуть різними, то така функція просто вважатиметься перевантаженою, а її "віртуальна суть" втратиться. Окрім того, віртуальна функція повинна бути членом класу, для якого вона визначається, а не його "другом". Але водночас віртуальна функція може бути "другом" іншого класу.

Варто знати! Функціям деструкторів дозволено бути віртуальними, а функціям конструкторів – ні.

16.2.2. Успадкування віртуальних функцій

Атрибут virtual передається "за успадкуванням".

Якщо функція оголошується як віртуальна, то вона залишається такою незалежно від того, через скільки рівнів похідних класів вона може пройти. Наприклад, якби клас secondD був виведений з класу firstD, а не з класу baseClass, як це показано в наведеному нижче прикладі, то функція who(), як і раніше, залишалася б віртуальною, і механізм вибору відповідної версії теж працював би коректно.

// Цей клас виведений з класу firstD, а не з baseClass.

class secondD: public firstD {

public:

// Перевизначення функції who() для класу secondD.

void who() { cout << "Другий похідний клас.\n";}

};

Якщо похідний клас не перевизначає віртуальну функцію, то використовується функція, яка була визначена в базовому класі. Наприклад, перевіримо, як поведеться версія попередньої програми, якщо у класі secondD не буде перевизначено функції who().

Код програми 16.3. Демонстрація механізму успадкування віртуальних функцій

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

 

class baseClass { // Оголошення базового класу

public:

virtual void who() { cout << "Базовий клас.\n";}

};

// Клас firstD виведений з класу baseClass

class firstD: public baseClass {

public:

void who() { cout << "Перший похідний клас.\n";}

};

class secondD: public baseClass {

// Функція who() тут взагалі не визначена.

};

 

int main ()

{

baseClass Base_ob; // Створення об'єкта базового типу

baseClass *p; // Створення покажчика на об'єкт базового типу

firstD First_ob; // Створення об'єкта похідного типу

secondD Second_ob; // Створення об'єкта похідного типу

 

p = &Base_ob; // Присвоєння адреси об'єкта базового класу

p->who(); // Доступ до функції who() класу baseClass

 

p = &First_ob; // Присвоєння адреси об'єкта похідного класу

p->who(); // Доступ до функції who() класу firstD

 

p = &Second_ob; // Присвоєння адреси об'єкта похідного класу

p->who(); /* Тут виконується звернення до функції who() класу baseClass,

оскільки у класі secondD вона не перевизначена. */

getch (); return 0;

}

Тепер у процесі виконання цієї програми на екран виводиться таке:

Базовий клас.

Перший похідний клас.

Базовий клас.

Як підтверджують отримані результати виконання цієї програми, оскільки функція who() не перевизначена похідним класом secondD, то під час її виклику за допомогою настанови p->who() (коли член р вказує на об'єкт Second_ob) виконується та версія функції who(), яку було визначено у базовому класі baseClass.

Варто знати! Успадковані властивості специфікатора virtual є ієрархічними. Тому, якщо попередній приклад змінити так, щоб клас secondD був виведений з класу firstD, а не з класу baseClass, то під час звернення до функції who() через об'єкт типу secondD буде викликано ту її версію, яка оголошена у похідному класі firstD, оскільки цей клас є "найближчим" (за ієрархічними "мірками") до класу secondD, а не функцію who() з тіла базового класу baseClass. Ці ієрархічні залежності демонструються на прикладі наведеної нижче програми.

Код програми 16.4. Демонстрація ієрархічної залежності

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

 

class baseClass { // Оголошення базового класу

public:

virtual void who() { cout << "Базовий клас.\n";}

};

// Клас firstD виведений з класу baseClass

class firstD: public baseClass {

public:

void who() { cout << "Перший похідний клас.\n";}

};

 

// Клас secondD тепер виведений з класу firstD, а не з класу baseClass.

class secondD: public firstD {

// Функція who() не визначена.

};

 

int main ()

{

baseClass Base_ob; // Створення об'єкта базового типу

baseClass *p; // Створення покажчика на об'єкт базового типу

firstD First_ob; // Створення об'єкта похідного типу

secondD Second_ob; // Створення об'єкта похідного типу

 

p = &Base_ob; // Присвоєння адреси об'єкта базового класу

p->who(); // Доступ до функції who() класу baseClass

 

p = &First_ob; // Присвоєння адреси об'єкта похідного класу

p->who(); // Доступ до функції who() класу firstD

 

p = &Second_ob; // Присвоєння адреси об'єкта похідного класу

p->who(); /* Тут виконується звернення до функції who()

класу firstD, оскільки у класі secondD її не перевизначено. */

 

getch (); return 0;

}

Внаслідок виконання цієї програми на моніторі буде відображено такі результати:

Базовий клас.

Перший похідний клас.

Перший похідний клас.

Як бачите, клас secondD тепер використовує версію функції who(), яка визначена| у класі firstD, оскільки вона знаходиться щонайближче в ієрархічному ланцюжку класів.

16.2.3. Потреба у застосуванні віртуальних функцій

Як наголошувалося на початку цього розділу, віртуальні функції у поєднанні з похідними типами дають змогу мові програмування C++ підтримувати динамічний поліморфізм. Поліморфізм істотний для об'єктно-орієнтованого програмування з однієї важливої причини: він забезпечує можливість деякому узагальненому класу визначати функції, які використовуватимуть усі похідні від нього класи, причому похідний клас може визначити власну реалізацію усіх або деяких цих функцій. Іноді ця ідея виражається так: базовий клас диктує загальний інтерфейс, який матиме будь-який об'єкт, який є виведеним з цього класу, але дає змогу при цьому похідному класу визначити метод, який використовують для реалізації цього інтерфейсу. Ось чому для опису поліморфізму часто використовують фраза "один інтерфейс, багато методів".

Для успішного застосування поліморфізму необхідно розуміти, що базовий і похідний класи утворюють ієрархію, розвиток якої спрямований від більшого до меншого ступеня узагальнення (тобто від базового класу до похідного). У разі коректного розроблення базовий клас забезпечує всі елементи, які похідний клас може використовувати безпосередньо. Він також визначає функції, які похідний клас повинен реалізувати самостійно. Це дає похідному класу гнучкість у визначенні власних методів, але водночас зобов'язує використовувати загальний інтерфейс. Іншими словами, оскільки формат інтерфейсу визначається базовим класом, будь-який похідний клас повинен розділяти цей загальний інтерфейс. Таким чином, використання віртуальних функцій дає змогу базовому класу визначати узагальнений інтерфейс, який буде використаний всіма похідними класами.

Тепер у Вас може виникнути запитання: чому ж такий важливий загальний інтерфейс з множиною реалізацій? Відповідь знову повертає нас до основної спонукальної причини виникнення об'єктно-орієнтованого програмування: такий інтерфейс дає змогу програмісту справлятися зі все зростаючою складністю програм. Наприклад, якщо коректно розробити програму, то можна бути упевненим у тому, що до всіх об'єктів, виведених з базового класу, можна буде отримати доступ єдиним (загальним для всіх) способом, незважаючи на те, що конкретні дії одного похідного класу можуть відрізнятися від дій іншого. Це означає, що програмісту доведеться пам'ятати тільки один інтерфейс, а не велику їх множину. Окрім того, похідний клас має можливість використовувати будь-які або всі функції, надані базовим класом. Іншими словами, розробнику похідного класу не потрібно наново винаходити елементи, які вже є в базовому класі. Понад це, відділення інтерфейсу від реалізації дає змогу створювати бібліотеки класів, написанням яких можуть займатися сторонні організації. Коректно реалізовані бібліотеки повинні надавати загальний інтерфейс, який програміст може використовувати для виведення класів відповідно до своїх конкретних потреб. Наприклад, як бібліотека базових класів Microsoft (Microsoft Foundation Classes – MFC), так і новіша бібліотека класів.NET Framework Windows Forms підтримують Windows-програмування. Використання цих класів дає змогу писати програми, які можуть успадкувати багато функцій, потрібних будь-якій Windows-програмі. Вам знадобиться тільки додати в неї засоби, унікальні для Вашої програми. Це – велика підмога під час програмування складних систем.

16.2.4. Приклад застосування віртуальних функцій

Щоб Ви могли отримати уявлення про силу принципу "один інтерфейс, багато методів", розглянемо таку коротку програму. Вона створює базовий клас figUre, призначений для зберігання розмірів різних двовимірних об'єктів і обчислення їх площ. Функція setDim() є стандартною функцією-членом, оскільки ця операція підходить для всіх похідних класів. Проте функція showArea() оголошена як віртуальна, оскільки методи обчислення площі різних об'єктів будуть різними. Програма використовує базовий клас figUre для виведення двох спеціальних класів rectAngle і triAngle.

Код програми 16.5. Демонстрація механізму застосування віртуальних функцій

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

 

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm) { x = izm; y = jzm;}

virtual void showArea() {

cout << "У цьому класі виразу для обчислення "

<< "площі не визначено.\n";}

};

class triAngle: public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle: public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

<< " має площу " << х * y << ".\n";}

};

 

int main ()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єктів похідних типів

rectAngle R_ob; // Створення об'єкта похідного типу

 

p = &T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

getch (); return 0;

}

Ось як виглядають результати виконання цієї програми:

Трикутник з висотою 10 і основою 5 має площу 25.

Прямокутник розмірами 10 х 5 має площу 50.

У цій програмі зверніть увагу на те, що під час роботи з класами rectAngle і triAngle використано однаковий інтерфейс, хоча у них реалізовані власні методи обчислення площі відповідних об'єктів.

Як Ви думаєте, використовуючи оголошення класу figUre, можна вивести клас cirCle для обчислення площі круга за заданим значенням радіуса? Відповідь: так. Для цього достатньо створити новий похідний тип, який би обчислював площу круга. Потужність віртуальних функцій опирається на той факт, що програміст може легко вивести новий тип, який розділятиме загальний інтерфейс з іншими "спорідненими" об'єктами. Ось, наприклад, як це можна зробити в нашому випадку:

class cirCle: public figUre {

public:

void showArea() {

cout << "Круг з радіусом " << x

<< " має площу " << 3.14 * х * х;}

};

Перш ніж випробувати клас cirCle в роботі, розглянемо уважно визначення функції showArea(). Звернемо Вашу увагу на те, що в ній використовується тільки одне значення змінної х, яка повинна містити радіус круга[66]. Проте, згідно з визначенням функції setDim(), у класі figUre їй передається два значення, а не одне. Оскільки класу cirCle не потрібне друге значення, то що ми можемо зробити? Є два способи вирішити цю проблему. Перший (і одночасно найгірший) полягає у тому, що ми могли б, працюючи з об'єктом класу cirCle, просто викликати функцію setDim(), передаючи їй як другий параметр фіктивне значення. Основний недолік цього методу – відсутність чіткості у задаванні параметрів і необхідність пам'ятати про спеціальні винятки, які порушують дію принципу: "один інтерфейс, багато методів".

Є вдаліший спосіб вирішення цього питання, який полягає у наданні параметру функції setDim() значення, що діє за замовчуванням. У цьому випадку під час виклику функції setDim() для круга потрібно задавати тільки радіус. Під час виклику ж функції setDim() для трикутника або прямокутника задають обидва значення. Нижче показано програму, у якій реалізований цей метод.

Код програми 16.6. Демонстрація надання параметру віртуальної функції значення,
що діє за замовчуванням

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

 

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm=0) { x = izm; y = jzm;}

virtual void showArea() {

cout << "Для цього класу вираз обчислення "

<< "площі не визначено.\n";}

};

class triAngle: public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle: public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

<< " має площу " << х * y << ".\n";}

};

class cirCle: public figUre {

public:

void showArea() {

cout << "Круг з радіусом " << x

<< " має площу " << 3.14 * x * x << ".\n";}

};

 

int main ()

{

figUre *p; // Створення покажчика на об'єкт базового типу

triAngle T_ob; // Створення об'єкта похідного типу

rectAngle R_ob; // Створення об'єкта похідного типу

cirCle C_ob; // Створення об'єкта похідного типу

 

p = &T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

p = &C_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(9.0);

p->showArea();

 

getch (); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

Трикутник з висотою 10 і основою 5 має площу 25.

Прямокутник розмірами 10 х 5 має площу 50.

Круг з радіусом 9 має площу 254.34.

Варто знати! Хоча віртуальні функції синтаксично прості для розуміння, їх справжні можливості неможливо продемонструвати на коротких прикладах. Як правило, потужність поліморфізму виявляється у великих складних системах. У міру засвоєння C++ Вам ще не раз буде надано можливість переконатися в їх корисності.

16.2.5. Суто віртуальні функції та абстрактні класи

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

Суто віртуальна функція – це віртуальна функція, яка не має визначення в базовому класі.

Існує два способи оброблення таких ситуацій. Перший (він показаний у попередньому прикладі коду програми) полягає у забезпеченні функцією виведення застережливого повідомлення. Можливо, такий підхід і буде корисний у певних ситуаціях, але здебільшого він просто неприйнятний. Наприклад, можна уявити собі віртуальні функції, без визначення яких у існуванні похідного класу взагалі немає ніякого сенсу. Розглянемо клас triAngle. Він абсолютно даремний, якщо у ньому не визначити функцію showArea(). У цьому випадку варто створити метод, який би гарантував, що похідний клас дійсно містить усі необхідні функції. У мові програмування C++ для вирішення цього питання і передбачено суто віртуальні функції.

Суто віртуальна функція – це функція, яка оголошена в базовому класі, але є такою, що не має у ньому ніякого визначення. Тому будь-який похідний тип повинен визначити власну версію цієї функції, адже у нього просто немає ніякої можливості використовувати версію з базового класу (через її відсутність). Щоб оголосити суто віртуальну функцію, використовують такий загальний формат:

virtual тип ім'я_функції (список_параметрів) = 0;

У цьому записі під елементом тип маємо на увазі тип значення, що повертається функцією, а елемент ім'я_функції – використовуване у програмі її ім'я. Позначення = 0 є ознакою того, що функція тут оголошується як суто віртуальна. Наприклад, в наступній версії визначення класу figUre функція showArea() вже представлена як суто віртуальна:

class figUre {

double x, y;

public:

void setDim(double izm, double jzm=0) { x = izm; y = jzm;}

virtual void showArea() = 0; // Суто віртуальна функція

};

Оголосивши функцію суто віртуальною, програміст створює умови, при яких похідний клас просто вимушений мати визначення власної її реалізації. Без цього компілятор видасть повідомлення про помилку. Наприклад, спробуйте скомпілювати цю модифіковану версію програми обчислення площ геометричних фігур, у якій з класу cirCle видалено визначення функції showArea().

Код програми 16.7. Демонстрація не коректної програми, яка у класі cirCle немає перевизначення функції showArea()

#include <iostream> // Для потокового введення-виведення

using namespace std; // Використання стандартного простору імен

 

class figUre {

protected:

double x, y;

public:

void setDim(double izm, double jzm) { x = izm; y = jzm;}

virtual void showArea() = 0; // Суто віртуальна функція

};

class triAngle: public figUre {

public:

void showArea() {

cout << "Трикутник з висотою " << x << " і основою " << y

<< " має площу " << х * 0.5 * y << ".\n";}

};

class rectAngle: public figUre {

public:

void showArea() {

cout << "Прямокутник розмірами " << х << " х " << y

<< " має площу " << х * y << ".\n";}

};

class cirCle: public figUre {

// Відсутність визначення функції showArea()

// Викличе повідомлення про помилку.

};

 

int main ()

{

figUre *p; // Створення покажчика на об'єкт базового типу

 

triAngle T_ob; // Створення об'єкта похідного типу

rectAngle R_ob; // Створення об'єкта похідного типу

 

cirCle С_ob; // Помилка: створення цього об'єкта є неможливим!

 

p = & T_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

p = &R_ob; // Присвоєння адреси об'єкта похідного класу

p->setDim(10.0, 5.0);

p->showArea();

 

getch (); return 0;

}

Якщо клас містить хоч би одну суто віртуальну функцію, то він називається абстрактним.

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

16.2.6. Порівняння раннього зв'язування з пізнім

Під час обговорення об'єктно-орієнтованих мов програмування зазвичай використовують два терміни: раннє зв'язування (early binding) і пізнє зв'язування (late binding). У мові програмування C++ ці терміни пов'язують з подіями, які відбуваються під час компілювання та у період виконання програми відповідно.

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

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

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

Відповідь на запитання: чому віддати перевагу – ранньому або пізньому зв'язуванню, залежить від призначення Вашої програми[67]. Пізнє зв'язування (його ще називають динамічним) це один з найпотужніших засобів мови програмування C++. Проте за цю потужність доводиться розплачуватися втратами у швидкості виконання програм. Тому пізнє зв'язування краще за все використовувати тільки у разі, коли воно істотно покращує структуру і керованість програмою. Як і всі практичні засоби, пізнє зв'язування, зазвичай, варто використовувати, але не зловживати ним. Викликані ним втрати у продуктивності є дуже незначні, тому, коли ситуація вимагає пізнього зв'язування, сміливо беріть його на озброєння.




Поделиться с друзьями:


Дата добавления: 2014-11-29; Просмотров: 412; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.166 сек.