69725

Віртуальні базові класи

Лекция

Информатика, кибернетика и программирование

Як вказано в коментарях, класи derivedl і derived2 є спадкоємцями класу base. Проте клас deribed3 є похідним від обох класів derived2 і derived1. (Таке наслідуванно називається діамантовим). Отже, в об’єкті класу derived3 містяться дві копії об’єкту класу base.

Украинкский

2014-10-09

42 KB

0 чел.

Тема 3: Віртуальні базові класи

При множинному наслідуванні може виникнути неоднозначність. Розглянемо, наприклад, наступну неправильну програму.

//  Ця програма містить  помилку і не  компілюється.

#include <iostream>

using namespace std;

class base   {

public:

int  i;

};

// Клас derivedl є спадкоємцем класу base.

class derivedl : public base {

public:

int j ;

};

// Клас derived2 є спадкоємцем класу base 

class derived2 : public base {

public:

int k;

};

/* Клас derived3 є спадкоємцем класів derivedl і derived2. Отже, в класі

derived3 існують дві копії класу base! */

class derived3 : public derivedl, public derived2 {

public:

int sum;

};

int main() {

derived3 ob;

ob.i = 10; ob.j = 20; ob.k = 30;

// Неоднозначність, яка змінна i мається

// Тут змінна i також визначена неоднозначно.

ob. sum = ob. i + ob. j + ob.k;

// Тут змінна i також визначена неоднозначно

cout << ob.i << " ";

cout « ob.j « " " « ob.k « " ";

cout << ob.sum;

return 0;

}

Як вказано в коментарях, класи derivedl і derived2 є спадкоємцями класу base. Проте клас deribed3 є похідним від обох класів derived2 і derived1. (Таке наслідуванно називається діамантовим). Отже, в об'єкті класу derived3 містяться дві копії об'єкту класу base. Таким чином, вираз

 ob.i  =  20;

у якому відбувається звернення до змінної i, стає неоднозначним, оскільки невідомо, з об'єкту якого класу слід узяти цю змінну: derivedl або derived2. Володіючи двома копіями об'єкту класу base, об'єкт класу ob містить два екземпляри змінної ob.i! Як видимий, цей оператор в принципі неоднозначний.

Цю програму можна виправити двома способами. По-перше, до змінній i можна застосувати оператора дозволу області видимості. Наприклад, наступна програма працює абсолютно правильно

//   У  цій програмі для  явного  вибору  змінної  i

//   застосовується  оператор дозволу  області видимості.

#include  <iostream>

using namespace  std;

class  base   {

public:

int   i ;

};

// Клас derivedl є спадкоємцем класу base

class derivedl : public base {

public:

int j ;

};

// Клас derived2 є спадкоємцем класу base 

class derived2 : public base {

public:

int k;

};

/* Клас derived3 є спадкоємцем класів derivedl і derived2 одночасно.

Отже, в кожному його об'єкті містяться дві копії об'єкту класу base! */

class derived3 : public derivedl, public derived2 {

public:

int sum;

};

int main() {

derived3 ob;

ob.derivedl::i = 10; // Неоднозначність усунена

// використовується змінна i з класу derivedl .

ob.j = 20; ob.k = 30;

// Неоднозначність усунена

ob.sum = ob.derivedl::i + ob.j + ob.k;

// Неоднозначність усунена

cout « ob.derivedl::i « " ";

cout « ob.j « " " « ob.k « " "; cout << ob.sum;

return 0;

}

Як видимий, оператор дозволу області видимості "::" дозволяє явно вибрати варіант похідного класу. Проте це рішення породжує нові проблеми. Що якщо насправді потрібна лише одна копія об'єкту класу base? Чи можна запобігти дублюванню об'єктів класу base в об'єкті класу derivad3? На обидва питання можна відповісти позитивно. Вирішення цих проблем засноване на застосуванні віртуальних базових класів (virtual base classes).

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

class derivedl : virtual public base {

public:

int j ;

};

// Клас derivedl є спадкоємцем віртуального класу base.

class derived2 : virtual public base {

public:

int k;

};

/* Клас derived3 є спадкоємцем класів derivedl і derived2.

Цього разу його об'єкт містить лише одну копію об'єкту базового класу. */

class derived3 : public derivedl, public derived2 {

public:

int sum;

};

Як видимий, перед ім'ям базового класу в специфікації похідного класу стоїть ключове слово virtual. Тепер обидва класи derivedl і derived2 є спадкоємцями віртуального базового класу base, і будь-які їх спадкоємці міститимуть лише одну копію класу base. Отже, об'єкт класу derived3 містить копію об'єкту класу base, і вираз ob.i=10 стає абсолютно правильним і однозначним.

Слід мати на увазі, що, хоча класи derivedl і derived2 оголосили клас base віртуальним, його об'єкти будуть як і раніше частиною об'єктів будь-якого з цих типів. Наприклад, наступний фрагмент є абсолютно правильним.

//   Визначуваний об'єкт  класу derivedl 

derivedl myclass; myclass.i  =   88;

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


 

А также другие работы, которые могут Вас заинтересовать

76502. Ограничение родительских прав 17.55 KB
  При лишении родительских прав родители ребёнка утрачивают право на личное воспитание в том числе на общение; на получение мер социальной поддержки: пособий компенсаций льгот. При ограничении родительских прав отец и мать утрачивают права на личное воспитание и получение льгот но сохраняют право на общение с ребенком если такое общение не оказывает на ребенка негативного вредного влияния. В каких случаях суд можно ограничить мать и отца в родительских правах Если ребенок находится в опасной обстановке которая возникла не по вине...
76503. Алиментные правоотношения супругов и бывших супругов 18.09 KB
  Супруги вправе заключить соглашение об уплате алиментов. проживающие как супруги без официальной регистрации брака в органах загса могут заключить соглашение о предоставлении содержания на которые нормы СК РФ регулирующие соглашения об уплате алиментов будут распространяться в порядке аналогии закона. В случае отказа от материальной поддержки и отсутствия соглашения между супругами об уплате алиментов право требовать предоставления алиментов в судебном порядке от другого супруга обладающего необходимыми для этого средствами имеют: а...
76504. Алиментные правоотношения родителей и детей 21.08 KB
  80 СК РФ Родители обязаны содержать своих несовершеннолетних детей.27 ГК РФ обязанность родителей содержать своих детей прекращается ст. Гражданский кодекс РФ наделяет детей достигших 14-летнего возраста заключать соглашение об уплате алиментов с согласия своего родителя или иного законного представителя ст.
76505. Алиментные правоотношения родителей и совершеннолетних детей 19.06 KB
  И здесь следует остановиться на соглашении об уплате алиментов. Соглашение об уплате алиментов способ добровольной уплаты алиментов. Родители вправе заключить соглашение о предоставлении алиментов своим совершеннолетним детям независимо от их нетрудоспособности и нуждаемости.
76506. Алиментные правоотношения других членов семьи 17 KB
  Трудоспособные совершеннолетние братья и сестры обладающие необходимыми средствами обязаны содержать своих нуждающихся в помощи несовершеннолетних братьев и сестер в случае невозможности получения ими содержания от своих родителей а также нетрудоспособных нуждающихся в помощи совершеннолетних братьев и сестер если они не могут получить содержание от своих трудоспособных совершеннолетних детей супругов бывших супругов или от родителей ст. 94 СК РФ предусмотрена алиментная обязанность дедушки и бабушки в отношении своих внуков. К...
76507. Соглашение об уплате алиментов (понятие, форма, содержание, правовое значение) 17.43 KB
  Заключить соглашение может также лицо не являющееся алиментообязанным когда нет оснований для назначения алиментов в судебном порядке. Соглашение об уплате алиментов должно быть заключено в письменной форме с последующим нотариальным удостоверением п. В содержании соглашения об уплате алиментов должны быть указаны размер алиментов; порядок и способы их уплаты.
76508. Порядок взыскания и уплаты алиментов 19.8 KB
  2 ст 104 Семейного кодекса РФ установлены следующие способы уплаты алиментов: долевой в процентах к заработку и или доходу плательщика; в твердой сумме уплачиваемой периодически; в твердой сумме уплачиваемой единовременно; путем предоставления имущества это может быть единовременно или периодически в согласованные периоды; смешанные варианты. 81 Семейного кодекса Российской Федерации размер алиментов зависит от материального или семейного положения сторон и иных заслуживающих внимания обстоятельств. Взыскание алиментов...
76509. Взыскание задолженности по алиментам 17.93 KB
  Задолженность по уплате алиментов может образоваться в двух случаях: Судом установлен размер алиментов в твердой денежной сумме однако алиментообязанное лицо по какимто причинам не платит положенные алименты. Судом установлен размер алиментов в процентах от заработка однако алиментообязанное лицо нигде не работает и не получает иного дохода. В первом случае расчет задолженности по алиментам не составляет особого труда: необходимо умножить количество месяцев в течение которых не производилась уплата алиментов на твердую денежную сумму...
76510. Прекращение алиментных правоотношений 17.14 KB
  Так если алиментные обязательства были установлены соглашением сторон об уплате алиментов то они согласно п. 120 СК прекращаются: смертью одной из сторон; истечением срока действия соглашения; по иным основаниям непосредственно предусмотренным соглашением об уплате алиментов например при восстановлении трудоспособности или прекращении нуждаемости бывшего супруга на содержание которого другим бывшим супругом выплачивались алименты. Что же касается алиментов взыскиваемых в судебном порядке то основания...