Multiple Inheritance
Point of Departure
Multiple inheritance with QObject is discussed further in Qt Quarterly.[3]
[3] http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
.3.3. Resolving Multiple Inheritance Conflicts
Figure 23.4 shows a UML diagram where multiple inheritance is being used incorrectly, for both interface and implementation. To make things even more complicated, we are inheriting from the same base class twice.
Figure 23.4. PersonStudentTeacher
Here, the class GradTeachingFellow is derived from two classes: Student and Teacher.
class GradTeachingFellow : public Student, public Teacher { // class member functions and data members };
Name conflicts and design problems can arise from the improper use of multiple inheritance. In the above example, geTDepartment() function exists in both Student and Teacher. The student could be studying in one department and teaching in another, for example.
What happens when you call geTDepartment() on a GraduateTeachingFellow?
GraduateTeachingFellow gtf; Person* pptr = >f; Student * sptr = >f;; Teacher* tptr = >f; gtf.Teacher::getDepartment(); gtf.Student::getDepartment(); sptr->getDepartment() tptr->getDepartment() pptr->getDepartment(); // ambiguous - run-time error if virtual gtf.getDepartment(); // Compiler error - ambiguous function call
The problem, of course, is that we have provided no getdepartment() function in the GradTeachingFellow class. When the compiler looks for a geTDepartment() function, Student and Teacher have equal priority.
Inheritance conflicts like these should be avoided because they lead to much design confusion later. However, in this case they can also be resolved with the aid of scope resolution.
.3.3.1. virtual Inheritance
In Figure 23.4, we inherited more than once from the same base class. There is another problem with that model: redundancy. When we create instances of this multiply inherited class, they might look like Figure 23.5.
Figure 23.5. GradTeachingFellownonvirtual
Person has attributes that we wish to inherit only once. It makes no sense for a GradTeachingFellow to have two birthdates and two names. virtual inheritance allows us to avoid the redundancy.
The strange problems that can arise when multiple inheritance is used in controversial ways, especially with the added complexities of virtual versus nonvirtual inheritance/functions, seem to have prompted the designers of Java to exclude multiple inheritance from their language. Instead, Java allows the programmer to define an interface, which consists only of abstract (pure virtual) functions. A Java class can then use the implements clause to implement as many interfaces as it needs.
.3.3.2. virtual Base Classes
A base class may be declared virtual. A virtual base class shares its representation with all other classes that have the same virtual base class.
Add the keyword virtual in the classHead as shown in Example 23.8, leaving all the other details of the class definitions the same.
Example 23.8. src/multinheritance/people.h
#include "qdatetime.h" class Person { public: Person(QString name, QDate birthdate) QObject(name.ascii()), m_Birthdate(birthdate) {} Person(const Person& p) : QObject(p), m_Birthdate(p.m_Birthdate) {} private: QDate m_Birthdate; }; class Student : virtual public Person { <-- 1 // other class members }; class Teacher : virtual public Person { <-- 2 // other class members } class GraduateTeachingFellow : public Student, public Teacher { <-- 3 public: GraduateTeachingFellow(const Person& p, const Student& s, const Teacher& t): Person(p), Students(s), Teacher(t) {} <-- 4 }
(1)Note keyword virtual here. (2)virtual inheritance (3)Virtual not needed here. (4)It is necessary to initialize all virtual base classes explicitly in multiply-derived classes, to resolve ambiguity about how they should be initialized. |
After using virtual inheritance, an instance of GradTeachingFellow might look like Figure 23.6.
Figure 23.6. GradTeachingFellowvirtual
Each instance of a class that virtually inherits from another has a pointer (or a variable offset) to its virtual base class subobject. The virtual base class pointer is invisible to the programmer and, in general, not necessary to change.
With multiple inheritance, each virtual base class pointer points to the same object, effectively allowing the base class object to be shared among all of the derived-class "parts."
For any class with a virtual base among its base classes, a member initialization entry for that virtual base must appear in the member initialization for that class. Otherwise, the virtual base gets default initialization.
Review Questions
1. | What is a vtable? |
2. | What is a polymorphic type? |
3. | Which kinds of member functions are not inherited? Why? |
4. | Under what circumstances should we have virtual destructors? |
5. | What happens when a virtual function is called from a base-class constructor? |
6. | What is virtual inheritance? What problems can it be used to solve? |
7. | Why would one use non-public derivation? |
Категории