Множественото наследяване в C ++ е мощен, но сложен инструмент, който често води до проблеми, ако не се използва внимателно - проблеми като Diamond Problem.

В тази статия ще обсъдим проблема с диаманта, как възниква от множественото наследяване и какво можете да направите, за да разрешите проблема.

Множествено наследяване в C ++

Множественото наследяване е a функция на обектно-ориентираното програмиране (ООП) където подклас може да наследи от повече от един суперклас. С други думи, дъщерният клас може да има повече от един родител.

Фигурата по -долу показва живописно представяне на множество наследства.

В горната диаграма, клас С има клас А и клас Б като неговите родители.

Ако разгледаме сценарий от реалния живот, едно дете наследява от баща си и майка си. Така че едно дете може да бъде представено като производен клас с „баща“ и „майка“ като негови родители. По подобен начин можем да имаме много такива реални примери за множествено наследяване.

При множествено наследяване конструкторите на наследен клас се изпълняват в реда, в който са наследени. От друга страна, деструкторите се изпълняват в обратен ред на наследяването им.

instagram viewer

Сега нека илюстрираме множественото наследяване и да проверим реда на изграждане и унищожаване на обекти.

Код Илюстрация на множествено наследяване

За илюстрацията на множествено наследяване ние точно сме програмирали горното представяне в C ++. Кодът на програмата е даден по -долу.

#включва
използване на пространство от имена std;
клас А // основен клас А с конструктор и деструктор
{
публично:
A () {cout << "клас A:: Конструктор" << endl; }
~ A () {cout << "клас A:: Деструктор" << endl; }
};
клас B // основен клас B с конструктор и деструктор
{
публично:
B () {cout << "клас B:: Конструктор" << endl; }
~ B () {cout << "клас B:: Деструктор" << endl; }
};
клас C: публичен B, публичен A // производен клас C наследява клас A и след това клас B (обърнете внимание на реда)
{
публично:
C () {cout << "клас C:: Конструктор" << endl; }
~ C () {cout << "клас C:: Деструктор" << endl; }
};
int main () {
C c;
връщане 0;
}

Резултатът, който получаваме от горната програма, е следният:

клас B:: Конструктор
клас A:: Конструктор
клас C:: Конструктор
клас C:: Деструктор
клас А:: Деструктор
клас B:: Деструктор

Сега, ако проверим изхода, виждаме, че конструкторите се извикват в ред B, A и C, докато деструкторите са в обратен ред. Сега, когато знаем основите на множественото наследяване, продължаваме да обсъждаме проблема с диаманта.

Диамантеният проблем, обяснен

Проблемът с диаманта възниква, когато дъщерният клас наследява от два родителски класа, които споделят общ клас баба и дядо. Това е илюстрирано на диаграмата по -долу:

Ето, имаме клас Дете наследяване от класове Татко и Майко. Тези два класа от своя страна наследяват класа Лице защото и бащата, и майката са Личност.

Както е показано на фигурата, клас Child наследява чертите на класа Person два пъти - веднъж от Баща и отново от Майка. Това поражда неясноти, тъй като компилаторът не разбира кой път да тръгне.

Този сценарий поражда графика на наследяване във формата на диамант и е известен като „Диамантеният проблем“.

Кодова илюстрация на проблема с диаманта

По-долу сме представили горния пример за наследяване под формата на диамант програмно. Кодът е даден по -долу:

#включва
използване на пространство от имена std;
class Person {// клас Person
публично:
Лице (int x) {cout << "Лице:: Лице (int) наречено" << endl; }
};
клас Баща: публично лице {// клас Бащата наследява Личност
публично:
Баща (int x): Лице (x) {
cout << "Баща:: Баща (int) наречен" << endl;
}
};
клас Майка: публично лице {// клас Майката наследява Лице
публично:
Майка (int x): Лице (x) {
cout << "Майка:: Майка (int) наречена" << endl;
}
};
клас Дете: обществен Баща, обществена Майка {// Детето наследява Баща и Майка
публично:
Дете (int x): Майка (x), Баща (x) {
cout << "Дете:: Дете (int) наречено" << endl;
}
};
int main () {
Дете дете (30);
}

Следва резултатът от тази програма:

Лице:: Извикано лице (int)
Баща:: Отец (int) се обади
Лице:: Извикано лице (int)
Майка:: Майка (int) се обади
Дете:: Извикано дете (int)

Сега можете да видите неяснотата тук. Конструкторът на клас Person се извиква два пъти: веднъж, когато е създаден обектът клас Баща и следващ, когато е създаден обектът клас Майка. Свойствата на класа Person се наследяват два пъти, което води до неяснота.

Тъй като конструкторът клас Person се извиква два пъти, деструкторът също ще бъде извикан два пъти, когато обектът клас Child е унищожен.

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

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

Решението на проблема с диаманта е да се използва виртуален ключова дума. Ние превръщаме двата родителски класа (които наследяват от един и същ клас баба и дядо) във виртуални класове, за да избегнем две копия на класа баба и дядо в дъщерния клас.

Нека променим горната илюстрация и проверим изхода:

Илюстрация на код за отстраняване на проблема с диаманта

#включва
използване на пространство от имена std;
class Person {// клас Person
публично:
Person () {cout << "Person:: Person () наречен" << endl; } // Основен конструктор
Лице (int x) {cout << "Лице:: Лице (int) наречено" << endl; }
};
клас Баща: виртуален публичен човек {// клас Бащата наследява Личност
публично:
Баща (int x): Лице (x) {
cout << "Баща:: Баща (int) наречен" << endl;
}
};
клас Майка: виртуално публично лице {// клас Майката наследява Лице
публично:
Майка (int x): Лице (x) {
cout << "Майка:: Майка (int) наречена" << endl;
}
};
клас Дете: обществен баща, обществена майка {// клас Дете наследява баща и майка
публично:
Дете (int x): Майка (x), Баща (x) {
cout << "Дете:: Дете (int) наречено" << endl;
}
};
int main () {
Дете дете (30);
}

Тук сме използвали виртуален ключова дума, когато класовете Баща и Майка наследяват класа Личност. Това обикновено се нарича „виртуално наследяване“, което гарантира, че се предава само един екземпляр от наследения клас (в този случай класът Person).

С други думи, класът Child ще има един екземпляр от класа Person, споделен както от бащата, така и от майката. Чрез наличието на един екземпляр от клас Person неяснотата се разрешава.

Резултатът от горния код е даден по -долу:

Лице:: Извикано лице ()
Баща:: Отец (int) се обади
Майка:: Майка (int) се обади
Дете:: Извикано дете (int)

Тук можете да видите, че конструкторът клас Person се извиква само веднъж.

Едно нещо, което трябва да се отбележи при виртуалното наследяване, е, че дори ако параметризираният конструктор на Класът Person се извиква изрично от конструкторите на баща и майка чрез инициализация списъци, ще бъде извикан само базовият конструктор на клас Person.

Това е така, защото има само един екземпляр на виртуален базов клас, споделен от множество класове, които наследяват от него.

За да се предотврати изпълнението на базовия конструктор няколко пъти, конструкторът за виртуален базов клас не се извиква от класа, наследяващ го. Вместо това конструкторът се извиква от конструктора на конкретния клас.

В горния пример клас Child директно извиква основния конструктор за класа Person.

Свързани: Ръководство за начинаещи в стандартната библиотека с шаблони в C ++

Ами ако трябва да изпълните параметризирания конструктор на базовия клас? Можете да направите това, като изрично го извикате в класа Child, а не в класовете баща или майка.

Диамантеният проблем в C ++, решен

Диамантеният проблем е неяснота, която възниква при множествено наследяване, когато два родителски класа наследяват от един и същи клас баба и дядо, а и двата родителски класа се наследяват от един дочерствен клас. Без да използва виртуално наследяване, дъщерният клас ще наследи свойствата на класа баба и дядо два пъти, което ще доведе до неяснота.

Това може да се появи често в реалния код, така че е важно да се обърне внимание на тази неяснота, когато се забележи.

Диамантеният проблем е решен с помощта на виртуално наследяване, при което виртуален ключовата дума се използва, когато родителските класове наследяват от споделен клас на баба и дядо. По този начин се прави само едно копие на класа баба и дядо, а конструирането на обекта на класа баба и дядо се извършва от дъщерния клас.

ДялТуителектронна поща
10 -те най -добри начинаещи проекта за нови програмисти

Искате да научите програмиране, но не знаете откъде да започнете? Тези проекти и уроци за програмиране за начинаещи ще ви започнат.

Прочетете Напред

Свързани теми
  • Програмиране
  • C Програмиране
За автора
Персонал на MUO

Абонирайте се за нашия бюлетин

Присъединете се към нашия бюлетин за технически съвети, рецензии, безплатни електронни книги и изключителни оферти!

Щракнете тук, за да се абонирате