adding the diamond problem
This commit is contained in:
committed by
JamesFlare1212
parent
3514476080
commit
e2c9cf9566
@@ -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:
|
||||
|
||||

|
||||
|
||||
## 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:
|
||||
|
||||
29
lectures/26_inheritance_II/diamond_test1.cpp
Normal file
29
lectures/26_inheritance_II/diamond_test1.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
32
lectures/26_inheritance_II/diamond_test2.cpp
Normal file
32
lectures/26_inheritance_II/diamond_test2.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#include <iostream>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user