diff --git a/lectures/26_inheritance_II/README.md b/lectures/26_inheritance_II/README.md index 83837eb..c889a48 100644 --- a/lectures/26_inheritance_II/README.md +++ b/lectures/26_inheritance_II/README.md @@ -2,16 +2,92 @@ ## 26.1 Multiple Inheritance -- When sketching a class hierarchy for geometric objects, you may have wanted to specify relationships that were more complex... in particular some objects may wish to inherit from more than one base class. -- This is called multiple inheritance and can make many implementation details significantly more hairy. Different programming languages offer different variations of multiple inheritance. -- See [example 1](multiple_inheritance1.cpp) and [example 2](multiple_inheritance2.cpp). +- Multiple inheritance allows a class to inherit from more than one base class. -- And see [example 3](multiple_level_inheritance.cpp) for a multiple level inheritance example. +- See [example 1](multiple_inheritance1.cpp) and [example 2](multiple_inheritance2.cpp). Note: ![alt text](Note_multipleInheritance.png "MultipleInheritance_note") +## 26.2 The Diamond Problem + +- The Diamond Problem occurs in multiple inheritance when two classes inherit from the same base class, and a fourth class inherits from both of those. + + Human + / \ + Student Worker + \ / + CSStudent + +- Both Student and Worker inherit from Human. + +```cpp +class Human { +public: + void speak(); +}; + +class Student : public Human {}; +class Worker : public Human {}; + +class CSStudent : public Student, public Worker {}; +``` + +- CSStudent inherits from both Student and Worker. + +- Compiler sees two Human base classes. + +- This leads to duplicate data and ambiguous member resolution. + +```cpp +CSStudent cs; +cs.speak(); // ❌ Ambiguous: which Human::speak()? +``` + +### Solution: Virtual Inheritance + +- Use the virtual keyword when inheriting the common base class. + +```cpp +class Student : virtual public Human {}; +class Worker : virtual public Human {}; +class CSStudent : public Student, public Worker {}; +CSStudent cs; +cs.speak(); // ✅ No ambiguity +``` + +- How it works: + + - Compiler ensures only one shared instance of Human. + + - Student and Worker do not create their own copies of Human. + + - Memory layout uses pointers behind the scenes to share the base. + +### Constructor Order with Virtual Inheritance + +When virtual inheritance is involved: + +Most derived class (e.g., CSStudent) is responsible for calling the base (Human) constructor. + +```cpp +class Human { +public: + Human(int age) {} +}; + +class Student : virtual public Human { +public: + Student() : Human(0) {} // ❌ Not allowed to call Human(int) here +}; + +class CSStudent : public Student { +public: + CSStudent() : Human(21), Student() {} // ✅ Human constructor called here +}; +``` + ## 26.2 Introduction to Polymorphism - Let’s consider a small class hierarchy version of polygonal objects: diff --git a/lectures/26_inheritance_II/diamond_test1.cpp b/lectures/26_inheritance_II/diamond_test1.cpp new file mode 100644 index 0000000..0371401 --- /dev/null +++ b/lectures/26_inheritance_II/diamond_test1.cpp @@ -0,0 +1,29 @@ +#include + +class Human { +public: + Human() { std::cout << "Human constructor\n"; } +}; + +class Student : public Human { +public: + Student() { std::cout << "Student constructor\n"; } +}; + +class Worker : public Human { +public: + Worker() { std::cout << "Worker constructor\n"; } +}; + +class CSStudent : public Student, public Worker { +public: + CSStudent() { std::cout << "CSStudent constructor\n"; } +}; + +// problem with this program: Human constructor runs twice! +int main() { + // CSStudent has two copies of Human, one via Student and one via Worker. + // Ambiguity: If we try to access a Human member from CSStudent, the compiler doesn’t know which one we mean. + CSStudent cs; + return 0; +} diff --git a/lectures/26_inheritance_II/diamond_test2.cpp b/lectures/26_inheritance_II/diamond_test2.cpp new file mode 100644 index 0000000..2433aaf --- /dev/null +++ b/lectures/26_inheritance_II/diamond_test2.cpp @@ -0,0 +1,32 @@ +#include + +class Human { +public: + Human() { std::cout << "Human constructor\n"; } +}; + +// The virutal keyword tells the compiler: +// "Hey, if this class is used in a diamond-like hierarchy, only one shared Human base should exist, no matter how many paths lead to it." +// The compiler then: Makes sure that only one instance of Human exists inside CSStudent. +class Student : virtual public Human { +public: + Student() { std::cout << "Student constructor\n"; } +}; + +class Worker : virtual public Human { +public: + Worker() { std::cout << "Worker constructor\n"; } +}; + +class CSStudent : public Student, public Worker { +public: + CSStudent() { std::cout << "CSStudent constructor\n"; } +}; + +// problem with this program: Human constructor runs twice! +int main() { + // CSStudent has two copies of Human, one via Student and one via Worker. + // Ambiguity: If we try to access a Human member from CSStudent, the compiler doesn’t know which one we mean. + CSStudent cs; + return 0; +}