Inheritance of C++ Expeditions (Part Two)
Multiple Inheritance and Multiple Inheritance
Multiple Inheritance:


class Person { }; class Soldier: public Person { }; class Infantryman: public Soldier { };
Multiple Inheritance:


class Worker { }; class Framer { }; class MigrantWorker: public Worker,public Framer { };
If not, the system defaults to private inheritance
Multiple Inheritance Code Demo

Person -> Soldier -> Infantryman
- Grandfather instantiates Grandpa first, then Dad.Finally, you can instantiate your grandchildren.

- The grandchildren die first.Then Dad died.Finally Grandpa died.
Appendix code:
#include <iostream> #include <stdlib.h> #include "Infantry.h" void test1(Person p) { p.play(); } void test2(Person &p) { p.play(); } void test3(Person *p) { p->play(); } int main() { Infantry infantry; system("pause"); return 0; } #include <string> using namespace std; class Person { public: Person(string name = "jim"); virtual ~Person();// Virtual destructor, inheritable.The soldier is also virtual. void play(); protected: string m_strName; }; #include "Person.h" #include <iostream> #include <string> using namespace std; Person::Person(string name) { m_strName = name; cout << "person()" << endl; } Person::~Person() { cout << "~person()" << endl; } void Person::play() { cout << "person - play()" << endl; cout << m_strName << endl; } #include "Person.h" #include <string> using namespace std; class Soldier :public Person { public: Soldier(string name = "james", int age = 20); virtual ~Soldier(); void work(); protected: string m_iAge; }; #include "Soldier.h" #include <iostream> using namespace std; Soldier::Soldier(string name, int age) { m_strName = name; m_iAge = age; cout << "Soldier()" << endl; } Soldier::~Soldier() { cout << "~Soldier()" << endl; } void Soldier::work() { cout << m_strName << endl; cout << m_iAge << endl; cout << "Soldier -- work" << endl; } #include "Soldier.h" class Infantry:public Soldier { public: Infantry(string name = "jack", int age = 30); ~Infantry(); void attack(); }; #include <iostream> #include "Infantry.h" using namespace std; Infantry::Infantry(string name /* = "jack" */, int age /* = 30 */) { m_strName = name; m_iAge = age; cout << "Infantry()" << endl; } Infantry::~Infantry() { cout << "~Infantry()" << endl; } void Infantry::attack() { cout << m_iAge << endl; cout << m_strName<< endl; cout << "Infantry --attack" << endl; }
**Infantry-isa Soldier-isa Human**
Transfer relationships.
int main() { Infantry infantry; test1(infantry); test2(infantry); test3(&infantry); system("pause"); return 0; }

Tes1 passes in an object.So there will be temporarily generated objects.And destroy it.
c++ Multiple Inheritance

The order in which the two parent classes are instantiated is consistent after the colon and is independent of the order in which the list is initialized.
class MigrantWorker:public Worker, public Framer
- Is superclass constructed in the order of inherited declarations, not in the order of initialization list
- Default values for function parameters are best set at declaration rather than at definition.Because the definition appears after the call, compiling it is unrecognized and then errors

Full code:
#include <string> using namespace std; class Worker { public: Worker(string code ="001"); virtual ~Worker(); void carry(); protected: string m_strCode; }; // // #include "Worker.h" #include <iostream> using namespace std; Worker::Worker(string code) { m_strCode = code; cout << "worker()" << endl; } Worker::~Worker() { cout << "~worker" << endl; } void Worker::carry() { cout << m_strCode << endl; cout << "worker -- carry()" << endl; } // // #include <string> using namespace std; class Framer { public: Framer(string name = "jack"); virtual ~Framer(); void sow(); protected: string m_strName; }; // // #include "Farmer.h" #include <iostream> using namespace std; Framer::Framer(string name) { m_strName = name; cout << "Framer()" << endl; } Framer::~Framer() { cout << "~Framer()" << endl; } void Framer::sow() { cout << m_strName << endl; cout << "sow()" << endl; } // // #include <string> #include "Farmer.h" #include "Worker.h" using namespace std; class MigrantWorker:public Worker, public Framer//This order determines the order of instantiation. { public: MigrantWorker(string name,string code); ~ MigrantWorker(); private: }; // // #include "MigrantWorker.h" #include <iostream> using namespace std; MigrantWorker::MigrantWorker(string name,string code): Framer(name), Worker(code) { cout <<":MigrantWorker()" << endl; } MigrantWorker::~MigrantWorker() { cout << "~MigrantWorker()" << endl; } // // #include <iostream> #include "MigrantWorker.h" #include <stdlib.h> int main() { MigrantWorker *p = new MigrantWorker("jim","100"); p->carry(); p->sow(); delete p; p = NULL; system("pause"); return 0; }

- You can use a pointer to the subclass to call his two dads'methods.
- Instantiation order: Declaration order.
- Destroy Order: Exactly the opposite
Consolidation exercises
- Define worker worker and child classes
- Data member m_strName name defined in worker class
- m_iAge age of member defined in children class
- Define ChildLabourer Child Labor Class, Public Inherited Worker Class, and Child Class
- Instantiate an object of the ChildLabourer class through new in the main function, call member functions in the worker and children classes through the object, and destroy the object. Understand more inherited inheritance properties and the execution order of constructors and destructors.
#include <iostream> #include <stdlib.h> #include <string> using namespace std; /** * Define worker class: Worker * Data member: m_strName * Member function: work() */ class Worker { public: Worker(string name) { m_strName = name; cout << "Worker" << endl; } ~Worker() { cout << "~Worker" << endl; } void work() { cout << m_strName << endl; cout << "work" << endl; } protected: string m_strName; }; /** * Define a child class: Children * Data member: m_iAge * Member function: play() */ class Children { public: Children(int age) { m_iAge = age; cout << "Children" << endl; } ~Children() { cout << "~Children" << endl; } void play() { cout << m_iAge << endl; cout << "play" << endl; } protected: int m_iAge; }; /** * Define child labor class: ChildLabourer * Public Inherited Workers and Children */ class ChildLabourer : public Children,public Worker { public: ChildLabourer(string name, int age):Children(age),Worker(name) { cout << "ChildLabourer" << endl; } ~ChildLabourer() { cout << "~ChildLabourer" << endl; } }; int main(void) { // Creating child labor objects using the new keyword ChildLabourer *c = new ChildLabourer("jim",10); // Calling parent work() and play() methods through child labor objects c -> work(); c -> play(); // release delete c; c = NULL; return 0; }

A base class does not need to define a virtual destructor. A virtual destructor is used when a parent pointer points to a child class object. It simply instantiates a child class object and executes a parent and child destructor when destroyed.
- A virtual destructor is designed to solve the problem that the pointer of the base class points to a derived class object in the heap and deletes the derived class object with the pointer of the base class.
- If the destructor is not a virtual function, the compiler implements static binding, and when deleting the base class pointer, only the destructor of the base class is called, not the destructor of the derived class
c++ Virtual Inheritance (Theory)
Multiple inheritance
- What about multiple inheritance and multiple inheritance?


As shown in the figure, assuming that class A is the parent class, class b and class C both inherit class a, and class d inherits class b and c, code redundancy occurs because class d inherits class a twice and multiple, resulting in two identical data members or member functions of class A.
People->Farmers|Workers->Migrant Workers
- You can use virtual inheritance if you want to avoid this
class Worker: virtual public Person // Equivalent to public virtual Person { }; class Framer: virtual public Person // Equivalent to public virtual Person { }; class MigrantWorker: public Worker,public Framer { };
Use virtual inheritance.Then the migrant workers will only have one inherited Person member.
Virtual Inheritance Code:

We have introduced Person.h in both framer and worker
When MigrantWorker inherits from both of them.Will introduce two Person s
- Resolve redefinition with macro definition:
We should write this in a class that is publicly inherited:
#ifndef PERSON_H//If not defined #define PERSON_H//Definition //Code // #endif //terminator
Appendix complete code:
#ifndef PERSON_H//If not defined #define PERSON_H//Definition #include <string> using namespace std; class Person { public: Person(string color = "blue"); virtual ~Person(); void printColor(); protected: string m_strColor; }; #endif //terminator // // #include <iostream> #include "Person.h" using namespace std; Person::Person(string color) { m_strColor = color; cout << "person()" << endl; } Person::~Person() { cout << "~Person()" << endl; } void Person::printColor() { cout << m_strColor << endl; cout << "Person -- printColor" << endl; } // // #include <string> using namespace std; #include "Person.h" class Worker:public Person { public: Worker(string code ="001",string color ="red");//Hope worker can pass in skin color to person virtual ~Worker(); void carry(); protected: string m_strCode; }; // // #include "Worker.h" #include <iostream> using namespace std; Worker::Worker(string code,string color):Person(color) { m_strCode = code; cout << "worker()" << endl; } Worker::~Worker() { cout << "~worker" << endl; } void Worker::carry() { cout << m_strCode << endl; cout << "worker -- carry()" << endl; } // // #include <string> using namespace std; #include "Person.h" class Framer:public Person { public: Framer(string name = "jack",string color = "blue"); virtual ~Framer(); void sow(); protected: string m_strName; }; // // #include "Farmer.h" #include <iostream> using namespace std; Framer::Framer(string name,string color):Person(color) { m_strName = name; cout << "Framer()" << endl; } Framer::~Framer() { cout << "~Framer()" << endl; } void Framer::sow() { cout << m_strName << endl; cout << "sow()" << endl; } // // #include <string> #include "Farmer.h" #include "Worker.h" using namespace std; class MigrantWorker:public Worker, public Framer//This order determines the order of instantiation. { public: MigrantWorker(string name,string code,string color); ~ MigrantWorker(); private: }; // // #include "MigrantWorker.h" #include <iostream> using namespace std; MigrantWorker::MigrantWorker(string name,string code,string color): Framer(name,color), Worker(code,color) { cout <<":MigrantWorker()" << endl; } MigrantWorker::~MigrantWorker() { cout << "~MigrantWorker()" << endl; } // // #include <iostream> #include "MigrantWorker.h" #include <stdlib.h> int main() { system("pause"); return 0; }
The ability to compile normally indicates that we successfully resolved the redefinition error with the macro definition for the diamond problem.
c++ Virtual Inheritance (Code 2)
Same as above.
int main() { MigrantWorker *p = new MigrantWorker("merry", "200", "yellow"); delete p; p = NULL; system("pause"); return 0; }

MigrantWorker now has two Person members.Let's prove it.
- Modify work.cpp and farmer:
Worker::Worker(string code,string color):Person("Worker"+color) Framer::Framer(string name,string color):Person("framer"+color)
- Print the two values with the pointer of the migrant workers.
main.cpp
int main() { MigrantWorker *p = new MigrantWorker("merry", "200", "yellow"); p->Framer::printColor(); p->Worker::printColor(); p = NULL; system("pause"); return 0; }

With virtual inheritance, only one share of migrant workers will be allowed.
class Worker: virtual public Person//work is a virtual base class. { }; class Framer:virtual public Person
Notice in C++ that virtual precedes common inheritance, meaning that it actually exists at the time of inheritance but cannot be accessed.

Consolidation exercises
- Defines Person, worker workers, and children s.
- The data member m_strName name is defined in the worker class.
- The age of the member m_iAge is defined in the children class.
- The worker class and the children class both have dummy inherited Person classes.
- Define ChildLabourer child labor classes, public inheritance worker classes, and child classes to form a diamond inheritance relationship
- Instantiate an object of the ChildLabourer class through new in the main function, call member functions in the Person, Worker and Children classes through this object, and finally destroy the object, master the definition of multiple inheritance, multiple inheritance, virtual inheritance.
#include <iostream> #include <stdlib.h> #include <string> using namespace std; /** * Define human: Person */ class Person { public: Person() { cout << "Person" << endl; } ~Person() { cout << "~Person" << endl; } void eat() { cout << "eat" << endl; } }; /** * Define worker class: Worker * Virtual inheritance of human */ class Worker : virtual public Person { public: Worker(string name) { m_strName = name; cout << "Worker" << endl; } ~Worker() { cout << "~Worker" << endl; } void work() { cout << m_strName << endl; cout << "work" << endl; } protected: string m_strName; }; /** * Define a child class:Children * Virtual inheritance of human */ class Children : virtual public Person { public: Children(int age) { m_iAge = age; cout << "Children" << endl; } ~Children() { cout << "~Children" << endl; } void play() { cout << m_iAge << endl; cout << "play" << endl; } protected: int m_iAge; }; /** * Define a child labor class: ChildLabourer * Public Inherited Workers and Children */ class ChildLabourer:public Children,public Worker { public: ChildLabourer(string name, int age):Worker(name),Children(age) { cout << "ChildLabourer" << endl; } ~ChildLabourer() { cout << "~ChildLabourer" << endl; } }; int main(void) { // Instantiating Child Labor Objects with the new Keyword ChildLabourer *p = new ChildLabourer("jim",15); // Call child labor object methods. p->eat(); p->work(); p->play(); delete p; p = NULL; return 0; }
Run result:
