Multiple inheritance with QObject is discussed further in Qt Quarterly.[3]
[3] http://doc.trolltech.com/qq/qq15-academic.html#multipleinheritance
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.
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.
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.
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.
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.
#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 }
|
After using virtual inheritance, an instance of GradTeachingFellow might look like Figure 23.6.
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.
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? |
Part I: Introduction to C++ and Qt 4
C++ Introduction
Classes
Introduction to Qt
Lists
Functions
Inheritance and Polymorphism
Part II: Higher-Level Programming
Libraries
Introduction to Design Patterns
QObject
Generics and Containers
Qt GUI Widgets
Concurrency
Validation and Regular Expressions
Parsing XML
Meta Objects, Properties, and Reflective Programming
More Design Patterns
Models and Views
Qt SQL Classes
Part III: C++ Language Reference
Types and Expressions
Scope and Storage Class
Statements and Control Structures
Memory Access
Chapter Summary
Inheritance in Detail
Miscellaneous Topics
Part IV: Programming Assignments
MP3 Jukebox Assignments
Part V: Appendices
MP3 Jukebox Assignments
Bibliography
MP3 Jukebox Assignments