Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
7
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

16.1. Покажчики на похідні типи – підтримка динамічного поліморфізму

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

Покажчик на базовий клас може посилатися на будь-який об'єкт, який є виведеним з цього базового класу.

У мові програмування C++ покажчик на базовий клас також можна використовувати для посилання на об'єкт будь-якого класу, виведеного з базового. Наприклад, припустимо, що у нас є базовий клас bClass і клас dClass, який виведений з класу bClass. У мові програмування C++ будь-який покажчик, оголошений як покажчик на клас bClass, може бути також покажчиком на клас dClass. Отже, після цих оголошень

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

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

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

обидві такі настанови є абсолютно законними:

p = &В_оb; // Покажчик p вказує на об'єкт типу bClass

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

/* Покажчик p вказує на об'єкт типу dClass, який є об'єктом,

що був виведений з класу bClass. */

У наведеному прикладі покажчик р можна використовувати для доступу до всіх елементів об'єкта D_ob, що є виведеним з об'єкта B_ob. Проте до елементів, які становлять специфічну "надбудову" (над базою, тобто над базовим класом bClass) об'єкта D_ob, доступ за допомогою покажчика р отримати не можна.

Як більш конкретний приклад розглянемо коротку програму, яка визначає базовий клас bClass і похідний клас dClass. У цій програмі проста ієрархія класів використовують для зберігання імен авторів і назв їх книг.

Код програми 16.1. Демонстрація механізму використання покажчиків на базовий клас для доступу до об'єктів похідних класів

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

#include <cstring> // Для роботи з рядковими типами даних

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

class bClass { // Оголошення класового типу

char author[80];

public:

void putAuthor(char *s) { strcpy(author, s);}

void showAuthor() { cout << author << "\n";}

};

class dClass : public bClass { // Оголошення класового типу

char title[80];

public:

void putTitle(char *num) { strcpy(title, num);}

void showTitle() { cout << "Назва: "; cout << title << "\n";}

};

int main()

{

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

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

dClass *dp; // Створення покажчика на об'єкт похідного типу

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

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

// Доступ до класу bClass через покажчик.

p->putAuthor("Еміль Золя|");

// Доступ до класу dClass через "базовий" покажчик.

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

p->putAuthor("Вільям Шекспір");

// Покажемо, що кожен автор належить до відповідного об'єкта.

B_ob.showAuthor();

D_ob.showAuthor();

cout << "\n";

/* Оскільки функції putTitle() і showTitle() не є частиною

базового класу, то вони недоступні через "базовий" покажчик p,

і тому до них потрібно звертатися або безпосередньо, або,

як показано тут, через покажчик на похідний тип. */

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

dp->putTitle("Буря");

p->showAuthor(); // Тут можна використовувати або покажчик p,

// або покажчик dp.

dp->showTitle();

getch(); return 0;

}

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

Еміль Золя|

Вільям Шекспір

Вільям Шекспір

Назва: Буря

У наведеному прикладі покажчик р визначається як покажчик на клас bClass. Але він може також посилатися на об'єкт похідного класу dClass, причому його можна використовувати для доступу тільки до тих елементів похідного класу, які успадковані від базового. Проте необхідно пам'ятати, що через "базовий" покажчик неможливо отримати доступ до тих членів, які специфічні для похідного класу. Ось чому до функції showTitle() звернення реалізується за допомогою покажчика dp, який є покажчиком на похідний клас.

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

((dClass *)p)->showTitle();

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

Крім того, необхідно розуміти: хоча "базовий" покажчик можна використовувати для доступу до об'єктів будь-якого похідного типу, зворотне ж твердження є неправильним. Іншими словами, використовуючи покажчик на похідний клас, не можна отримати доступ до об'єкта базового типу.

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

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

Посилання на похідні типи

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