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

Int mainO

{

derivedC ObjC;

ObjC.c = 10; // Це і є неоднозначність: який саме член с маємо на увазі???

ObjC.d = 20;

ObjC.f = ЗО;

//1 тут теж спостерігається неоднозначність з членом с.

ObjC.sum = ObjC.c + ObjC.d + ObjC.f;

//1 тут теж неоднозначність з членом с.

cout« ObjC.c «"";

cout« ObjC.d «"" « ObjC.f«"";

cout« ObjC.sum;

getchO; return 0;

}

Як зазначено у коментарях до цієї програми, обидва класи derivedA і derivedB успадковують клас baseClass. Але клас derivedC успадковує як клас derivedA, так і клас derivedB. У результаті в об'єкті типу derivedC присутні дві копії класу baseClass, тому у такому виразі

ObjC.c = 20;

не зрозуміло, на яку саме копію члена с тут дане посилання: на член, успадкова­ний від класу derivedA або від класу derivedB? Оскільки в об'єкті ObjC є обидві копії класу baseClass, то у ньому існують і два члени ObjC.c! Через це настанова с є ус­падкуванням неоднозначним (істотно невизначеним).

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

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

#include <vcl>

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

#include <сопіо> // Для консольного режиму роботи

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

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

};

// Клас derivedA успадковує клас baseClass. class derivedA: public baseClass { public: intd;

};

// Клас derivedB успадковує клас baseClass. class derivedB : public baseClass { public: int f;

};

І* Клас derivedC успадковує обидва класи derivedA і derivedB.

Це означає, що у класі derivedC існує дві копії класу baseClass! */

class derivedC : public derivedA, public derivedB {

public:

int sum;

};

Int mainO

{

derivedC ObjC;

ObjC.derivedA::c = 10; // Контекст дозволений, використовується член с класу derivedA. ObjC.d = 20;

ObjC.f = ЗО;

// Контекст дозволений і тут.

ObjC.sum = ObjC derivedA:+ ObjC.d + ObjC.f;

// Виникнення неоднозначності ліквідована і тут. cout« ObjC.derivedA::_x «""; cout« ObjC.d «"" « ObjC.f«""; cout« ObjC .sum;

getchO; return 0;

}

Застосування оператора дає змогу програмі "ручним способом" вибрати версію класу baseClass (успадковану класом derivedA). Але після такого рішення ви­никає цікаве запитання: а що, коли насправді потрібна тільки одна копія класу ba­seClass? Чи можна якимсь чином запобігти включенню двох копій у клас derivedC?

Відповідь, як, напевно, Ви здогадалися, позитивна. Це рішення досягається за до­помогою віртуальних базових класів.

Якщо два (або більше) класи виведено із загального базового класу, то ми можемо запобігти включенню декількох його копій в об'єкті, виведеному з цих класів, що реалізується шляхом оголошення базового класу під час його успадку­вання віртуальним. Для цього достатньо, щоби імені успадкованого базового кла­су передувало ключове слово virtual.

Віртуальне успадкування базового класу гарантує, що в будь-якому похідному класі наявна тільки одна його копія.

Для ілюстрації цього процесу наведемо ще одну версію попереднього коду програми. Цього разу клас derivedC містить тільки одну копію класу baseClass.

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

#include <vcl> #include <iostream> #include <conio> using namespace std;

базових класів

// Для потокового введення-виведення // Для консольного режиму роботи // Використання стандартного простору імен

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

};

// Клас derivedA успадковує клас baseClass як віртуальний, class derivedA: virtual public baseClass { public: intd;

};

// Клас derivedB успадковує клас baseClass як віртуальний, class derivedB : virtual public baseClass { public: intf;

};

P Клас derivedC успадковує обидва класи derivedA і derivedB. Цього разу він містить тільки одну копію класу baseClass. */ class derivedC : public derivedA, public derivedB { public:

int sum;

};