Вишеструко наслеђивање у Ц ++ је моћно, али шкакљиво средство, које често доводи до проблема ако се не користи пажљиво - проблема попут Дијамантског проблема.

У овом чланку ћемо разговарати о дијамантском проблему, о томе како он настаје из више наслеђа и шта можете учинити да решите проблем.

Више наслеђивања у Ц ++

Вишеструко наслеђивање је а карактеристика објектно оријентисаног програмирања (ООП) где подкласа може наследити више од једне суперкласе. Другим речима, подређена класа може имати више родитеља.

Доња слика приказује сликовни приказ више наслеђа.

На горњем дијаграму, класа Ц. хас хас класа А. и класа Б. као његови родитељи.

Ако узмемо у обзир сценарио из стварног живота, дете наслеђује од оца и мајке. Тако се дете може представити као изведена класа са „оцем“ и „мајком“ као родитељима. Слично томе, можемо имати много таквих примера вишеструког наслеђивања у стварном животу.

У више наслеђивања, конструктори наслеђене класе се извршавају редоследом којим су наслеђени. С друге стране, деструктори се извршавају обрнутим редоследом од њиховог наслеђивања.

Хајде сада да илуструјемо вишеструко наслеђивање и верификујемо редослед изградње и уништавања објеката.

Код Илустрација вишеструког наслеђивања

За илустрацију више наслеђивања, тачно смо програмирали горњу репрезентацију у Ц ++. Код програма дат је испод.

#инцлуде
коришћење простора имена стд;
класа А // основна класа А са конструктором и деструктором
{
јавно:
А () {цоут << "класа А:: Конструктор" << ендл; }
~ А () {цоут << "цласс А:: Деструцтор" << ендл; }
};
класа Б // основна класа Б са конструктором и деструктором
{
јавно:
Б () {цоут << "класа Б:: Конструктор" << ендл; }
~ Б () {цоут << "класа Б:: Деструктор" << ендл; }
};
класа Ц: јавна Б, јавна А // изведена класа Ц наслеђује класу А, а затим класу Б (обратите пажњу на редослед)
{
јавно:
Ц () {цоут << "класа Ц:: Конструктор" << ендл; }
~ Ц () {цоут << "класа Ц:: Деструцтор" << ендл; }
};
инт маин () {
Ц ц;
ретурн 0;
}

Резултат који добијамо из горњег програма је следећи:

класа Б:: Конструктор
класа А:: Конструктор
класа Ц:: Конструктор
класа Ц:: Деструцтор
класа А:: Деструктор
класа Б:: Деструктор

Сада, ако проверимо излаз, видимо да су конструктори позвани по редоследу Б, А и Ц, док су деструктори обрнутим редоследом. Сада када знамо основе вишеструког наслеђивања, прелазимо на расправу о дијамантском проблему.

Објашњење дијамантског проблема

Дијамантски проблем настаје када подређена класа наследи од две родитељске класе које обе деле заједничку класу деда и деда. Ово је илустровано доњим дијаграмом:

Ево, имамо час Цхилд наслеђујући од класа Оче и Мајко. Ове две класе, пак, наслеђују класу Особа јер су и Отац и Мајка Личност.

Као што је приказано на слици, класа Дете два пута наслеђује особине класе Особа - једном од оца и поново од мајке. Ово изазива нејасноће јер компајлер не разуме којим путем да иде.

Овај сценарио доводи до дијаграма наслеђа у облику дијаманта и познат је под називом „Дијамантски проблем“.

Кодна илустрација проблема дијаманата

У наставку смо програмски представили горњи пример наслеђивања у облику дијаманта. Код је дат испод:

#инцлуде
коришћење простора имена стд;
цласс Персон {// цласс Персон
јавно:
Особа (инт к) {цоут << "Особа:: Особа (инт) звана" << ендл; }
};
разред Отац: јавна особа {// разред Отац наслеђује Личност
јавно:
Отац (инт к): Особа (к) {
цоут << "Отац:: Отац (инт) зван" << ендл;
}
};
класа Мајка: јавна особа {// класа Мајка наслеђује особу
јавно:
Мајка (инт к): Особа (к) {
цоут << "Мајка:: Мајка (инт) звана" << ендл;
}
};
разред Дете: јавни Отац, јавна Мајка {// Дете наслеђује Оца и Мајку
јавно:
Дете (инт к): Мајка (к), Отац (к) {
цоут << "Цхилд:: Цхилд (инт) цаллед" << ендл;
}
};
инт маин () {
Дете дете (30);
}

Ово је резултат овог програма:

Особа:: Позвана особа (инт)
Отац:: Отац (инт) позван
Особа:: Позвана особа (инт)
Мајка:: Мајка (инт) звана
Дете:: Позвано дете (инт)

Сада можете видети нејасноће овде. Конструктор класе Персон се позива два пута: једном када је креиран објекат класе Отац и следећи када је креиран објекат класе Мајка. Својства класе Особа се наслеђују два пута, што доводи до нејасноћа.

Пошто се конструктор класе Персон позива два пута, деструктор ће се такође позвати два пута када се објекат класе Цхилд уништи.

Сада, ако сте правилно разумели проблем, хајде да разговарамо о решењу дијамантског проблема.

Како решити проблем дијаманта у Ц ++

Решење дијамантског проблема је употреба виртуелни кључна реч. Од две родитељске класе (које наслеђују из исте класе деда и бака) претварамо у виртуелне класе како бисмо избегли две копије класе деда и деда у дечијој класи.

Променимо горњу илустрацију и проверимо излаз:

Илустрација кода за решавање проблема са дијамантом

#инцлуде
коришћење простора имена стд;
цласс Персон {// цласс Персон
јавно:
Персон () {цоут << "Особа:: Особа () звана" << ендл; } // Конструктор базе
Особа (инт к) {цоут << "Особа:: Особа (инт) звана" << ендл; }
};
класа Отац: виртуелна јавна особа {// класа Отац наслеђује Личност
јавно:
Отац (инт к): Особа (к) {
цоут << "Отац:: Отац (инт) зван" << ендл;
}
};
класа Мајка: виртуелна јавна особа {// класа Мајка наслеђује особу
јавно:
Мајка (инт к): Особа (к) {
цоут << "Мајка:: Мајка (инт) звана" << ендл;
}
};
разред Дете: јавни Отац, јавна Мајка {// разред Дете наслеђује Оца и Мајку
јавно:
Дете (инт к): Мајка (к), Отац (к) {
цоут << "Цхилд:: Цхилд (инт) цаллед" << ендл;
}
};
инт маин () {
Дете дете (30);
}

Овде смо користили виртуелни кључна реч када класе Отац и Мајка наслеђују класу Особа. Ово се обично назива „виртуелно наслеђивање“, што гарантује да се преноси само једна инстанца наслеђене класе (у овом случају класе Особа).

Другим речима, класа Цхилд ће имати једну инстанцу класе Персон, коју деле и класе Отац и Мајка. Имајући једну инстанцу класе Персон, нејасноће се решавају.

Резултат горњег кода је дат испод:

Особа:: Позвана особа ()
Отац:: Отац (инт) позван
Мајка:: Мајка (инт) звана
Дете:: Позвано дете (инт)

Овде можете видети да се конструктор класе Персон позива само једном.

Једна ствар коју треба приметити код виртуелног наслеђивања је да чак и ако је параметризовани конструктор датотеке Конструктори класе Отац и Мајка путем иницијализације изричито позивају класу особа листе, позваће се само основни конструктор класе Персон.

То је зато што постоји само једна инстанца виртуелне основне класе коју дели више класа које је наслеђују.

Да би се спречило да се основни конструктор више пута не покреће, конструктор за виртуелну базну класу не позива класа која га наслеђује. Уместо тога, конструктор позива конструктор конкретне класе.

У горњем примеру, класа Цхилд директно позива основни конструктор за класу Персон.

Повезан: Водич за почетнике у библиотеци стандардних предложака у Ц ++

Шта ако требате да извршите параметризовани конструктор основне класе? То можете учинити тако што ћете то изричито назвати у класи детета, а не у разредима Отац или Мајка.

Дијамантски проблем у Ц ++, решен

Дијамантски проблем је нејасноћа која настаје при вишеструком наслеђивању када две родитељске класе наслеђују од исте класе деда и деда, а обе родитељске класе наслеђује једна подређена класа. Без коришћења виртуелног наслеђивања, подређена класа би два пута наследила својства класе деда и деда, што би довело до нејасноћа.

Ово се често може појавити у коду у стварном свету, па је важно да се та нејасноћа реши кад год се примети.

Дијамантски проблем решен је виртуелним наслеђивањем, у коме се виртуелни кључна реч се користи када родитељске класе наслеђују од дељене класе деда и деда. На тај начин се прави само једна копија класе деда и деда, а конструкцију објекта класе деда и деда врши класа цхилд.

ОбјавиТвеетЕмаил
10 најбољих пројеката за почетнике за нове програмере

Желите да научите програмирање, али не знате одакле да почнете? Ови пројекти и водичи за програмирање почетника ће вас покренути.

Прочитајте следеће

Повезане теме
  • Програмирање
  • Ц Програмирање
О аутору
Особље МУО

Претплатите се на наш билтен

Придружите се нашем билтену за техничке савете, критике, бесплатне е -књиге и ексклузивне понуде!

Кликните овде да бисте се претплатили