Inheritance of Mucho-C++ Expedition (Part 2) - Learning Notes

Inheritance of C++ Expeditions (Part Two)

Multiple Inheritance and Multiple Inheritance

Multiple Inheritance:


multiple inheritance

Multiple Inheritance-Is-a Relationship
class Person
{

};
class Soldier: public Person
{

};
class Infantryman: public Soldier
{

}; 

Multiple Inheritance:


Inherit more - a son has two dads

Multi-inheritance-isa-but peasants and workers have nothing to do with it
class Worker
{

};
class Framer
{

};
class MigrantWorker: public Worker,public Framer
{

};

If not, the system defaults to private inheritance

Multiple Inheritance Code Demo


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

Grandson-Dad-Grandpa's life and death
  • 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;
}

is-a passed by test1, 2, 3

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

c++ Multiple Inheritance


Multiple Inheritance Requirements

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

Multiple Inheritance-Instantiation and Destruction

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;
}



Multiple Inheritance-Instantiation and Destruction
  • 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;
}

Not using virtual functions is also possible

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?

Multiple Inheritance and Multiple Continuation of the Diamond Problem (Diamond Inheritance)

Diamonds

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:


Virtual Inheritance Requirements

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;
}

Life and Death in Diamond Objects

MigrantWorker now has two Person members.Let's prove it.

  1. Modify work.cpp and farmer:
Worker::Worker(string code,string color):Person("Worker"+color)
Framer::Framer(string name,string color):Person("framer"+color)
  1. 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;
}

Operation results: two out of the migrant workers

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.


After virtual inheritance, grandchildren can only get the value of grandparents when they call them

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:


Run Results

Added by saish on Wed, 29 May 2019 20:00:15 +0300