Зміст курсу
C++ ООП
C++ ООП
Діамантове Наслідування
Множинне наслідування може призвести до ситуації, відомої як проблема ромба або ромбовидне наслідування, що є суттєвою складністю в мовах об'єктно-орієнтованого програмування, які підтримують множинне наслідування.
Це виникає, коли підклас наслідується від двох або більше classes
, які самі наслідуються від спільного базового класу. Термін ромб використовується тому, що схема наслідування нагадує форму ромба.
main.cpp
class Base {}; class Derived1 : public Base {}; class Derived2 : public Base {}; class Diamond : public Derived1, public Derived2 {};
Основна проблема ромбовидного наслідування — це неоднозначність, яку воно створює. Оскільки Diamond
наслідується як від Derived1
, так і від Derived2
, які, у свою чергу, наслідуються від Base
, в об'єкті класу Base
існують дві копії Diamond
. Це може призвести до неоднозначності.
main.cpp
#include <iostream> class Base { public: void display() { std::cout << "Base display()" << std::endl; } }; class Derived1 : public Base { }; class Derived2 : public Base { }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.display(); // Ambiguity: Which display() method should be called? }
Розв'язання проблеми
Ключове слово virtual
допомагає уникнути цієї проблеми. Ви можете вирішити цю неоднозначність за допомогою віртуального наслідування, використовуючи ключове слово virtual
. Коли Diamond
наслідує віртуально, C++ гарантує, що існує лише одна копія суперкласу, навіть якщо він наслідується кілька разів через різні шляхи.
main.cpp
class Base {}; class Derived1 : virtual public Base {}; class Derived2 : virtual public Base {}; class Diamond : public Derived1, public Derived2 {};
Спробуйте вирішити проблему неоднозначності у попередньому прикладі, використовуючи віртуальне наслідування.
Реалізація ромбовидного наслідування
Для ефективної реалізації ромбовидного наслідування використовуйте ключове слово virtual у визначенні базового класу в проміжних classes
. Забезпечте послідовне використання віртуального наслідування на всіх шляхах ієрархії наслідування та звертайте увагу на порядок виклику конструкторів і деструкторів.
Усунення неоднозначностей
Одним із викликів множинного наслідування є також вирішення потенційних неоднозначностей, коли йдеться про члени з однаковими іменами.
main.cpp
#include <iostream> class Base {}; class Derived1 : public Base { public: void display() { std::cout << "Derived1 display()" << std::endl; } }; class Derived2 : public Base { public: void display() { std::cout << "Derived2 display()" << std::endl; } }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.display(); // Ambiguity: Which display() method should be called? }
Якщо обидва базові класи мають члени з однаковими іменами, похідний клас може не знати, який саме використовувати. Для вирішення таких неоднозначностей можна скористатися оператором розв'язання області видимості (::
), щоб вказати, до якого члена базового класу звертатися. Наприклад:
main.cpp
#include <iostream> class Base {}; class Derived1 : public Base { public: void display() { std::cout << "Derived1 display()" << std::endl; } }; class Derived2 : public Base { public: void display() { std::cout << "Derived2 display()" << std::endl; } }; class Diamond : public Derived1, public Derived2 { }; int main() { Diamond obj; obj.Derived1::display(); obj.Derived2::display(); }
Дякуємо за ваш відгук!