Simple explanation of C++ inheritance and derivation

1, Base and derived classes

A class can derive from another class. The former is called a base class or parent class, or a derived class or child class. A derived class can derive from a base class or multiple base classes. The former is called single inheritance and the latter is called multiple inheritance.

The single inheritance definition format is as follows:

class Derived class: inheritance mode base class
{
	A newly defined member of a derived class;
};

There are three inheritance methods: public private protected
Public inheritance, private inheritance, protected inheritance

The multi inheritance definition format is as follows:

class Derived class: inheritance method 1 base class 1, inheritance method 2 base class 2....
{
	Derived class new definition member;
};

Three ways to define derived classes
(1) Public inheritance
Public inheritance: public, the access properties of the public and protected members of the base class remain unchanged in the derived class, while the private members of the base class are inaccessible, that is, the public and protected members of the base class are the public and protected members of the derived class respectively, and other members of the derived class can access them directly.

(2) Protect inheritance
Protected inheritance: protected, * * the public and protected members of the base class can be inherited into the derived class, but the access properties become protected, * * and the private members of the base class can not be accessed, that is, the public and protected members of the base class are treated as protected members, and other members of the derived class can directly access them. Therefore, objects of subclasses cannot directly access inherited members of the base class. If you want to access inherited members, you must access them through member functions and friend functions.

(3) Private inheritance
When the inheritance method of a derived class is private, the public and protected members of the * * base class can be inherited into the derived class, but the access properties become private properties. The private members of the * * base class cannot be accessed, that is, the public and protected members of the base class are both private members of the derived class. If you want to access inherited members, you must access them through member functions and friend functions.

2, Single inheritance

1. member access control

#include<iostream>
using namespace std;

class A
{
    public:
        void f1();
        A(){i1 = 10;j1 = 11;}

    protected:
        int j1;
    
    private:
        int i1;
};

class B:public A
{
    public:
        void f2();
        B(){i2 = 20;j2 = 21;}

    protected:
        int j2;
    
    private:
        int i2;
};

class C:public B
{
    public:
        void f3();
        C(){i3 = 30;j3 = 31;}

    protected:
        int j3;

    private:
        int i3;
};

The member function f2() of derived class B can directly access the member f1() j1 in base class A, but cannot access i1
Object B of derived class B can directly access member f1() of base class A, but cannot directly access i1 j1
The member function of derived class C can directly access the member f2() j2 of base class B, but cannot directly access i2. It can also indirectly access the member f1() j1 of base class A, and cannot indirectly access i1
Object C of derived class C can directly access f1() of base class B and f1() of insight base class A, which cannot be accessed by other stores

In a word, in public inheritance, member functions of derived classes can directly access public members and protected members of the base class; Objects of derived classes can only access public members in the base class

2. design and execution of constructor in single inheritance
The constructor cannot be inherited. Therefore, the constructor of a derived class must initialize the base class sub object by calling the constructor of the base class. Therefore, when defining the constructor of a derived class, in addition to initializing its own data members, it must also be responsible for initializing the data members of the base class when calling the constructor of the base class.

The general format of the constructor of a derived class is as follows:

Derived class name (derived class constructor total parameter table): base class constructor (parameter table 1), sub object name (parameter table 2)
{
	Initialization of data members of derived classes;
};

The constructor call order of the derived class is as follows:
Constructor of base class
Constructor of sub object class (if any)
derived class constructor

#include<iostream>
using namespace std;

class A
{
    public:
        A(){cout<<"A Constructor"<<endl;}
};

class B:public A
{
    public:
        B(){cout<<"B Constructor"<<endl;}
};

int main(void)
{
    B b;
    system("pause");
    return 0;
}

Running results

First execute the constructor of A, and then execute the constructor of B.

3. execution process of destructor in single inheritance
The destructor cannot be inherited. The destructor of the derived class is executed first, and then the destructor of the base class. That is, the execution order is exactly the opposite to that of the constructor.


In practical applications, you should pay attention to the following issues when using derived class constructors:
1. the derived class constructor definition can omit the call to the base class constructor, provided that there must be a default constructor or no constructor defined in the base class.
2. when the constructor of the base class uses one or more parameters, the derived class must define a constructor to provide a way to pass parameters to the constructor of the base class

4. convert derived class objects to base class objects
Public inheritance: since a derived class has corresponding members of each base class (the members of a derived class are usually more than the members of a base class), it is reasonable for an object of a derived class to be assigned to a base class object, but the reverse is not true, because a derived class has a member definition that the base class does not have. Derived classes can be assigned to base class objects. A derived class object is also a base class object, so a pointer to a derived class object can also be implicitly converted to a pointer to a base class object.

Collocation:
Reference the base class object directly with the base class pointer
Reference a derived class object directly with a derived class pointer
Reference a derived class object with a base class pointer. Only base class members can be referenced
It is wrong to use a derived class pointer to reference an object of a base class. The derived class pointer must first be converted to a base class pointer

#include<iostream>
using namespace std;

class A
{
    private:
        int a;

    public:
        void setA(int X)
        {
            a = X;
        }
        void dispa()
        {
            cout<<"a  = "<<a << endl;
        }
};

class B:public A
{
    private:
        int b;

    public:
        void setB(int Y)
        {
            b = Y;
        }

        void dispb()
        {
            cout<<"b = "<<b<<endl;
        }
};

int main(void)
{
    A *pa = new A();
    pa->setA(1);
    pa->dispa();

    B *pb = new B();
    pb->setB(2);
    pb->dispb();

    A *pc = new B();//Subclass object assigned to base class this is allowed
    pc->setA(3);
    pc->dispa();

    B *pd = new B();
    A obj;
    obj.setA(4);
    pd = (B *)&obj;
    pd->dispa();

    system("pause");
    return 0;
}

3, Multiple inheritance

class C:public A,public B

1. design and execution of constructor in multi inheritance
Multiple inheritance has a total parameter table, and each base class has its own parameter table. Therefore, the number of parameters of the derived class must include the number of parameters of all base classes

The execution order of derived class constructors is as follows:
1. call the constructor of the base class from left to right
2. call constructor of sub object from left to right
3. call the constructor of the derived class

#include<iostream>
using namespace std;

class A
{
    private:
        int a;

    public:
        A(int i)
        {
            a = i;
            cout<<"A Constructor"<<endl;
        }

        void Disp()
        {
            cout<<"A = "<<a<<endl;
        }
};

class B
{
    private:
        int b;

    public:
        B(int i)
        {
            b = i;
            cout<<"B Constructor"<<endl;
        }

        void Disp()
        {
            cout<<"B = "<<b<<endl;
        }
};

class C:public A,public B
{
    private:
         int c;
    
    public:
        C(int k):A(k - 2),B(k + 3)   //Initialization list constructor containing base class members initializes the base class before initializing the derived class
        {
            c = k;
            cout<<"C Constructor"<<endl;
        }

        void disp()
        {
            A::Disp();//Calling a member function of a base class
            B::Disp();
            cout<<"c = "<<c<<endl;
        }
};

int main(void)
{
    C obj(10);
    obj.disp();
    system("pause");
    return 0;
}

2. destructor execution in multi inheritance
Execute in reverse order to constructor

3. ambiguity
In the above code, both base classes of derived class C contain the disp() function, but there is a ambiguity about which base class member function to access. Therefore, the:: scope operator is used for qualification

Tags: C++ Class

Posted by vandana on Mon, 30 May 2022 19:49:24 +0530