The basis of c + + language class -- multi inheritance of class and its constructor and destructor

Keywords: C++ C#

Inheritance of C + + language classes

1. Inheritance can be understood as the process by which a class obtains member variables and member functions from another class. For example, if class B inherits from Class A, then B has member variables and member functions of A.

2. Inheritance mechanism is an important means of object-oriented programming and code reuse. It allows programmers to expand and increase functions while maintaining the original characteristics of classes. In this way, a new class, called derived class, is generated. Inheritance reflects the hierarchical structure of object-oriented design and the cognitive process from simple to complex.

3. In C + +, derivation and inheritance are a concept, but from different angles. Inheritance is that the son receives the father's estate, and derivation is that the father inherits the estate to the son.

4. The inherited class is called parent class or base class, and the inherited class is called child class or derived class. "Child class" and "parent class" are usually called together, and "base class" and "derived class" are usually called together.

5. In addition to the members of the base class, a derived class can also define its own new members to enhance the function of the class.

Inherited usage scenarios:

  1. When the new class you create is similar to the existing class, but there are several more member variables or member functions, you can use inheritance, which will not only reduce the amount of code, but also have all the functions of the base class.
  2. Inheritance can also be used when you need to create multiple classes that have many similar member variables or member functions. The common members of these classes can be extracted, defined as the base class, and then inherited from the base class, which can not only save code, but also facilitate subsequent modification of members.

Three forms of inheritance

1) Public inheritance - Public: the public of the base class becomes the public of the derived class, the protection of the base class becomes the protection of the derived class, and the private derived class is inaccessible

1,	All in base class public Member is in a derived class public Attributes;
2,	All in base class protected Member is in a derived class protected Attributes;
3,	All in base class private Members cannot be used in derived classes.
4,	Access the base class in a derived class private The only way to a member is to use the non - class of the base class private Member function, if the base class has no non private Member function, the member will not be accessible in the derived class.

2) Private inheritance - Private: the public of the base class becomes the private of the derived class, the protection of the base class becomes the private of the derived class, and the private of the base class is inaccessible

1,	All in the base class public Member is in a derived class protected Attributes;
2,	All in the base class protected Member is in a derived class protected Attributes;
3,	All in the base class private Members cannot be used in derived classes.

3) Protect inheritance - protect: the public of the base class becomes the protection of the derived class, the protection of the base class becomes the protection of the derived class, and the private of the base class is inaccessible

1,	All in the base class public Members are in derived classes private Attributes;
2,	All in the base class protected Members are in derived classes private Attributes;
3,	All in the base class private Members cannot be used in derived classes.

Source code (1)

#include<iostream>
using namespace std;

class people{
	protected:
		int age;
		char *name;
		int hight;
	public:
		void get_people(int old,char *str,int h);
};

void people::get_people(int old,char *str,int h)
{
	age = old;
	name = str;
	hight = h;
}

class father:public people{
	protected:
		char *work;
		char *hobby;
	public:
		void get_father(char *str1,char *str2);
};

void father::get_father(char *str1,char *str2)
{
	work = str1;
	hobby = str2;
}

class son:public father{
	private:
		int Engligh_score;
		int math_score;
		char *son_name; 
	public:
	void get_son(char *str3,int x,int y);
	void show();
};

void son::get_son(char *str3,int x,int y)
{
	son_name = str3;
	Engligh_score = x;
	math_score = y;
	cout<<"Initialization sentence complete:"<<endl;
}

void son::show()
{
	cout<<"A father's name is"<<name<<endl<<"What is his age"<<age<<" "<<"What is his height"<<hight<<endl;
	cout<<"he"<<work<<endl<<hobby<<endl;
	cout<<son_name<<endl<<"What was his English score"<<Engligh_score<<" "<<"What's your math score"<<math_score<<endl; 
}

int main()
{
	son text;
	text.get_people(45,"Xiao Ming",176);
	text.get_father("Work as a programmer","His biggest hobby is waiting for money");
	text.get_son("Xiaohua is Xiaoming's son",89,87);
	text.show();
	return 0;
}

Source code (2)

#include<iostream>
using namespace std;

//Base class Pelple
class People{
public:
    void setname(char *name);
    void setage(int age);
    char *getname();
    int getage();
private:
    char *m_name;
    int m_age;
};
void People::setname(char *name){ m_name = name; }
void People::setage(int age){ m_age = age; }
char* People::getname(){ return m_name; }
int People::getage(){ return m_age;}

//Derived class Student
class Student: public People{
public:
    void setscore(float score);
    float getscore();
private:
    float m_score;
};
void Student::setscore(float score){ m_score = score; }
float Student::getscore(){ return m_score; }

int main(){
    Student stu;
    stu.setname("Xiao Ming");
    stu.setage(16);
    stu.setscore(95.5f);
    cout<<stu.getname()<<"What is your age "<<stu.getage()<<",The result is "<<stu.getscore()<<endl;

    return 0;
}

Change inherited permissions

Use the using keyword to change the access permissions of base class members in derived classes, such as changing public to private and protected to public.
Note: using can only change the access permissions of public and protected members in the base class, not private members. Because private members in the base class are invisible in derived classes and cannot be used at all, private members in the base class cannot be accessed in derived classes.

Source code (3)

#include<iostream>
using namespace std;

//Base class People
class People {
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
void People::show() {
    cout << m_name << "What is your age" << m_age << endl;
}

//Derived class Student
class Student : public People {
public:
    void learning();
public:
    using People::m_name;  //Change protected to public
    using People::m_age;  //Change protected to public
    float m_score;
private:
    using People::show;  //Change public to private
};
void Student::learning() {
    cout << "I am" << m_name << ",this year" << m_age << "Years old, I passed the exam this time" << m_score << "Points!" << endl;
}

int main() {
    Student stu;
    stu.m_name = "Xiao Ming";
    stu.m_age = 16;
    stu.m_score = 99.5f;
    stu.show();  //compile error
    stu.learning();

    return 0;
}

The masking of member functions in class inheritance

If the members in the derived class (including member variables and member functions) have the same name as the members in the base class, the members inherited from the base class will be masked. The so-called masking means that when using this member in a derived class (including when defining a derived class and accessing the member through a derived class object), it actually uses the new member of the derived class rather than inheriting from the base class.

In a word, you are a son, I am a father, I have 100
Dollars, you need to buy things at this time, and it happens that I also want to buy things. The things we both want to buy are the same. At this time, I will give money to buy things for your son. After all, it's good to have an errand runner to buy things. The money is spent by my son at this time.

Source code (1)

#include<iostream>
using namespace std;

//Base class People
class People{
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
void People::show(){
    cout<<"Hi, everyone. My name is"<<m_name<<",this year"<<m_age<<"year"<<endl;
}

//Derived class Student
class Student: public People{
public:
    Student(char *name, int age, float score);
public:
    void show();  //Mask show() of base class
private:
    float m_score;
};
Student::Student(char *name, int age, float score){
    m_name = name;
    m_age = age;
    m_score = score;
}
void Student::show(){
    cout<<m_name<<"What is your age"<<m_age<<",The result is"<<m_score<<endl;
}

int main(){
    Student stu("Xiao Ming", 16, 90.5);
    //The new member function of the derived class is used, not inherited from the base class
    stu.show();
    //Member functions inherited from the base class are used
    stu.People::show();

    return 0;
}

Overloading of member functions of base and derived classes

When the names of base class members and derived class members are the same, it will cause masking. This sentence is well understood for member variables. Pay attention to member functions. No matter what the parameters of the function are, as long as the names are the same, it will cause masking. In other words, the base class member function and the derived class member function will not constitute an overload. If the derived class has a function with the same name, it will mask all functions with the same name in the base class, whether their parameters are the same or not.
In other words, the overload problem of such a subclass is similar to the masking problem of member functions of base and derived classes

Source code (1)

#include<iostream>
using namespace std;

//Base class base
class Base{
public:
    void func();
    void func(int);
};
void Base::func(){ cout<<"Base::func()"<<endl; }
void Base::func(int a){ cout<<"Base::func(int)"<<endl; }

//Derived class
class Derived: public Base{
public:
    void func(char *);
    void func(bool);
};
void Derived::func(char *str){ cout<<"Derived::func(char *)"<<endl; }
void Derived::func(bool is){ cout<<"Derived::func(bool)"<<endl; }

int main(){
    Derived d;
    d.func("c.biancheng.net");
    d.func(true);
    d.func();  //compile error
    d.func(10);  //compile error
    d.Base::func();
    d.Base::func(100);

    return 0;
}

Constructors for C + + language base and derived classes

If a derived class has a constructor, when the main function calls the derived class member constructor, you must first call the member constructor of the base class, otherwise the system will report an error.

Source code (1) - correct example

#include<iostream>
using namespace std;

//Base class People
class People{
protected:
    char *m_name;
    int m_age;
public:
    People(char*, int);
};
People::People(char *name, int age): m_name(name), m_age(age){}

//Derived class Student
class Student: public People{
private:
    float m_score;
public:
    Student(char *name, int age, float score);
    void display();
};
//People(name, age) is to call the constructor of the base class
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
    cout<<m_name<<"What is your age"<<m_age<<",The result is"<<m_score<<". "<<endl;
}

int main(){
    Student stu("Xiao Ming", 16, 90.5);
    stu.display();

    return 0;
}

Source code (2) - error example

#include<iostream>
using namespace std;

class A{
	public:
		A(int a,int b);
		void show();
	private:
		int x;
		int y;
}; 

A::A(int a,int b)
{
	x = a;
	y = b;
} 

void A::show() 
{
	cout<<"x The value of is:"<<x<<" "<<"y The value of is:"<<y<<endl;
	 
}

class B:public A{
	public :
		B(int m);
		void show_B();
	private:
		int c;
};

B::B(int m)
{
	c = m;
} 

void B::show_B() 
{
	cout<<"c The value of is:"<<c<<endl;
}

int main()
{
	 B text(3);
	 text.show();
	 text.show_B();
	return 0;
}

The main reason for the above error example is that the constructor of the base class is not invoked in the derived class, causing the system to report errors.

In popular words, you are my son and I am your father. Why can you eat hot and spicy, and I, a father, can only eat the rest of you. It must be unfair. Therefore, before my son is popular and drinks spicy food, he must be filial to my father.

Main error code segment:
B::B(int m)
{
	c = m;
} 
Correct code example:
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }

Regardless of the calling order, the derived class constructor always calls the base class constructor before executing other code (including the parameter initialization table and the code in the function body)

be careful:

Student::Student(char *name, int age, float score){
People(name, age);
m_score = score;
}

The code written in this way is wrong, because the base class constructor will not be inherited and cannot be called as an ordinary member function. In other words, you can only put the call of the base class constructor at the head of the function, not in the body of the function.
In addition, the function header is a call to the base class constructor, not a declaration, so the parameters in parentheses are arguments. They can not only be parameters in the parameter list of the derived class constructor, but also local variables, constants, etc.

Order of constructor calls

The base class constructor is always called first, which means that when creating a derived class object, the base class constructor will be called first, and then the derived class constructor will be called,

If the inheritance order of multiple classes is:
A --> B --> C
 Then create C Class object, the execution order of the constructor is:
A class constructor  --> B class constructor  --> C class constructor 

The call order of constructors is from top to bottom, from the base class to the derived class according to the inheritance level.
It should also be noted that the derived class constructor can only call the constructor of the direct base class, not the constructor of the indirect base class. Take classes A, B and C above as examples. C is the final derived class. B is the direct base class of C and A is the indirect base class of C.

There is a reason why you cannot directly call the constructor of the indirect class, for example, the inheritance order above, the constructor of class A is initialized first, and then the constructor of class B is called. If the C class calls B constructor again, the constructor of class A is initialized two times. This greatly wastes CPU memory.

Call rules for constructors

In fact, when creating an object through a derived class, you must call the constructor of the base class, which is the syntax. In other words, it is better to specify the base class constructor when defining the derived class constructor; If not specified, call the default constructor of the base class (constructor without parameters); If there is no default constructor, the compilation fails.

Source code (1)

#include <iostream>
using namespace std;

//Base class People
class People{
public:
    People();  //Base class default constructor
    People(char *name, int age);
protected:
    char *m_name;
    int m_age;
};
People::People(): m_name("xxx"), m_age(0){ }
People::People(char *name, int age): m_name(name), m_age(age){}

//Derived class Student
class Student: public People{
public:
    Student();
    Student(char*, int, float);
public:
    void display();
private:
    float m_score;
};
Student::Student(): m_score(0.0){ }  //Derived class default constructor
Student::Student(char *name, int age, float score): People(name, age), m_score(score){ }
void Student::display(){
    cout<<m_name<<"What is your age"<<m_age<<",The result is"<<m_score<<". "<<endl;
}

int main(){
    Student stu1;
    stu1.display();

    Student stu2("Xiao Ming", 16, 90.5);
    stu2.display();

    return 0;
}

Destructors for base and derived classes of C + + language

Like constructors, destructors cannot be inherited. Unlike constructors, there is no need to explicitly call the destructor of the base class in the destructor of the derived class, because each class has only one destructor,

In addition, the execution order of destructors and constructors is just the opposite:
When creating a derived class object, the execution order of the constructor is the same as the inheritance order, that is, the base class constructor is executed first, and then the derived class constructor is executed.

When destroying a derived class object, the execution order of the destructor is opposite to the inheritance order, that is, the derived class destructor is executed first, and then the base class destructor is executed.

Source code (1)

#include <iostream>
using namespace std;

class A{
public:
    A(){cout<<"A constructor"<<endl;}
    ~A(){cout<<"A destructor"<<endl;}
};

class B: public A{
public:
    B(){cout<<"B constructor"<<endl;}
    ~B(){cout<<"B destructor"<<endl;}
};

class C: public B{
public:
    C(){cout<<"C constructor"<<endl;}
    ~C(){cout<<"C destructor"<<endl;}
};

int main(){
    C test;
    return 0;
}

Source code (2)

#include<iostream>
using namespace std;

class A//Define a base class A
{
public:
	A()
	{
		cout << "creat A process success!" << endl;
	}
	~A()
	{
		cout << "destroy A process success!" << endl;
	}
	void circle(int i)
	{
		if (i == 1)
			cout << "I am class A's father!" << endl;
		else if (i == 0)
			cout << "I am child A,you are my son!" << endl;
	}
};

class B : public A//Class B inherits class A
{
public:
	B()
	{
		cout << "creat B process success!" << endl;
	}
	~B()
	{
		cout << "destroy B process success!" << endl;
	}
	void circle1(int i)
	{
		if (i == 1)
			cout << "I am class B's father!" << endl;
		else if (i == 0)
			cout << "I am child B,you are my son!" << endl;
	}
};

void display_A(A* test,int a)//Access class A
{
	test->circle(a);
}

void display_B(B* test, int b)//You can access both class A and class B
{
	test->circle(b);
	test->circle1(b);
}

int main()
{
	A* test1=NULL;
	B* test2=NULL;
	int a = 1;
	int b = 0;
	display_A(test1, a);
	display_B(test2, b);
	//test2->~A();// Class a destructors can be destroyed first, but when class B calls the destructor,
	//Class A destructors are called again, which increases the running time and burden of the program.
	test2->~B();
	return 0;
}

Multi inheritance of C + + language classes

Class has more than one inheritance. There is only one base class in a derived class, which is called single inheritance. When two or more base classes are inherited simultaneously in a derived class, it is called multiple inheritance.

The syntax of multiple inheritance is also very simple. Multiple base classes can be separated by commas. For example, a class has been declared A,class B And class C,Then you can declare derived classes like this D: 
class D: public A, private B, protected C{
    //New members of class D
}

The constructor in multiple inheritance forms is basically the same as the single inheritance form. It only calls the constructors of many base classes in the constructor of the derived class.

The calling order of the base class constructor is independent of the the order in which they appear in the derived class constructor, but the same order in which the base class appears when the derived class is declared.

Generally speaking, a son inherits the heritage of multiple fathers, which is divided into the heritage of the eldest father, the second father, the third father and so on. Then when the son eats, he must eat first, but the father eats first, and the fathers eat first according to the order of size.

Source code (1)

#include <iostream>
using namespace std;

//Base class
class BaseA{
public:
    BaseA(int a, int b);
    ~BaseA();
protected:
    int m_a;
    int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
    cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
    cout<<"BaseA destructor"<<endl;
}

//Base class
class BaseB{
public:
    BaseB(int c, int d);
    ~BaseB();
protected:
    int m_c;
    int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
    cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
    cout<<"BaseB destructor"<<endl;
}

//Derived class
class Derived: public BaseA, public BaseB{
public:
    Derived(int a, int b, int c, int d, int e);
    ~Derived();
public:
    void show();
private:
    int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
    cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
    cout<<"Derived destructor"<<endl;
}
void Derived::show(){
    cout<<m_a<<", "<<m_b<<", "<<m_c<<", "<<m_d<<", "<<m_e<<endl;
}

int main(){
    Derived obj(1, 2, 3, 4, 5);
    obj.show();
    return 0;
}

Naming conflict of multiple inherited classes

When two or more base classes have a member with the same name, if you directly access the member, there will be a naming conflict. The compiler does not know which base class member to use. At this time, you need to add the class name and domain resolver:: before the member name to explicitly indicate which class member to use and eliminate ambiguity.

Source code (1)

#include <iostream>
using namespace std;

//Base class
class BaseA{
public:
    BaseA(int a, int b);
    ~BaseA();
public:
    void show();
protected:
    int m_a;
    int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
    cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
    cout<<"BaseA destructor"<<endl;
}
void BaseA::show(){
    cout<<"m_a = "<<m_a<<endl;
    cout<<"m_b = "<<m_b<<endl;
}

//Base class
class BaseB{
public:
    BaseB(int c, int d);
    ~BaseB();
    void show();
protected:
    int m_c;
    int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
    cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
    cout<<"BaseB destructor"<<endl;
}
void BaseB::show(){
    cout<<"m_c = "<<m_c<<endl;
    cout<<"m_d = "<<m_d<<endl;
}

//Derived class
class Derived: public BaseA, public BaseB{
public:
    Derived(int a, int b, int c, int d, int e);
    ~Derived();
public:
    void display();
private:
    int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
    cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
    cout<<"Derived destructor"<<endl;
}
void Derived::display(){
    BaseA::show();  //Call the show() function of the BaseA class
    BaseB::show();  //Call the show() function of the BaseB class
    cout<<"m_e = "<<m_e<<endl;
}

int main(){
    Derived obj(1, 2, 3, 4, 5);
    obj.display();
    return 0;
}

It is hereby declared that part of the text language description and code block of the article are transferred to this website

Posted by twm on Sun, 03 Oct 2021 15:54:30 -0700