C + + inheritance and derivation

Keywords: C++

definition

Class inheritance is a new class that obtains existing features from existing classes. Or the process of generating a new class from an existing class is the derivation of the class. The original class is called the base class or parent class, and the new class is called the derived class or child class. Derivation and inheritance are two appellations with the same meaning.

1. Succession

1.1 syntax

class Derived class name:[Inheritance mode] Base class name
{
	Derived class member declaration;
};

A derived class can have multiple base classes at the same time, which is called multiple inheritance. A derived class has only one base class, which is called single inheritance. Let's start with single inheritance.

1.2 inheritance method

The inheritance method specifies how to access members inherited from the base class. Inheritance methods include public, private and protected. The inheritance method does not affect the access rights of derived classes, but affects the access rights of members inherited from the base class, including the access rights in derived classes and derived class objects.

Public inheritance: public members and protected members of the base class maintain the original access properties in the derived class, and their private members are still private members of the base class.

Private inheritance: the public and protected members of the base class become private members in the derived class, and their private members are still private members of the base class.

Protected inheritance: the public and protected members of the base class become protected members in the derived class, and their private members are still private members of the base class.

For external access properties, predicted is equivalent to private, but can be visible in derived classes.

1.3 composition of derived classes

The members of a derived class include two parts: one is inherited from the base class, and the other is added by itself. Inherited from the base class shows its commonness, while the new members reflect its individuality.

1.4 precautions

1. Full reception, except constructors and destructors. The base class may cause redundancy of members of derived classes, so the base class needs to be designed.
2. The derived class has its own personality, which makes the derived class meaningful.

2. Construction of derived classes

The initialization of members inherited from the base class in the derived class is still completed by the constructor of the base class, and then the new members in the derived class are initialized in the constructor of the derived class.

2.1 syntax of derived class constructor

Derived class name::Derived class name (parameter summary table)
	:Base class name (parameter table),Embedded sub object (parameter table)
{
	Initialization statement of new member of derived class; //It can also appear in the parameter list
}
  • Constructors are initialized not in the above order, but in the declared order.
  • If there is no default constructor (no parameter) in the base class, the constructor of the derived class must show that the calling base class constructor is used to initialize the base class members.
  • Order of execution of derived class constructors:
 Base class-->member-->Subclass

a call the base class constructor in the order declared when they are inherited (from left to right);
b call the constructor of embedded member objects in the order they are declared in the class;
c the contents of the constructor body of the derived class.

2.2 code example

Grandfather class
student.h

class Student
{
public:
	Student(string sn,int n,char s);
	~Student();
	void dis();
private:
	string name;
	int num;
	char sex;
};

student.cpp

Student::Student(string sn, int n, char s)
	:name(sn),num(n),sex(s)
{
}
Student::~Student()
{
}
void Student:: dis()
{
	cout<<name<<endl;
	cout<<num<<endl;
	cout<<sex<<endl;
}

Parent class
graduate.h

class Graduate:public Student
{
public:
	Graduate(string sn,int in,char cs,float fs);
	~Graduate();
	void dump()
	{
		dis();
		cout<<salary<<endl;
	}
private:
	float salary;
};

graduate.cpp

Graduate::Graduate(string sn, int in, char cs, float fs)
	:Student(sn,in,cs),salary(fs)
{
}
Graduate::~Graduate()
{
}

Class member
birthday.h

class Birthday
{
public:
	Birthday(int y,int m,int d);
	~Birthday();
	void print();
private:
	int year;
	int month;
	int day;
};

bithday.cpp

Birthday::Birthday(int y, int m, int d)
	:year(y),month(m),day(d)
{
}
Birthday::~Birthday()
{
}
void Birthday::print()
{
	cout<<year<<month<<day<<endl;
}

Subclass
doctor.h

class Doctor:public Graduate
{
public:
	Doctor(string sn,int in,char cs,float fs,string st,int iy,int im,int id);
	~Doctor();
	void disdump();
private:
	string title; //The default constructor called, initialized as "Birthday birth"; 			
	Birthday birth; //Class object declared in class
};

doctor.cpp

Doctor::Doctor(string sn, int in, char cs, float fs, string st, int iy,int im, int id)
	:Graduate(sn,in,cs,fs),birth(iy,im,id),title(st)
{
}
Doctor::~Doctor()
{
}
void Doctor::disdump()
{
	dump();
	cout<<title<<endl;
	birth.print();
}

main.cpp

int main()
{
	Student s("1",2001,'m');
	s.dis();
	cout<<"----------------"<<endl;
	Graduate g("2",2001,'x',2000);
	g.dump();
	cout<<"----------------"<<endl;
	Doctor d("3",2001,'y',3000,"doctor",2001,8,16);
	d.disdump();
	return 0;
}

2.3 summary

In the subclass constructor, either the constructor of the parent class (passing parameters) is displayed or implicitly called. When an implicit call occurs, the parent class must have a parameterless constructor or a default parameter function that can contain a parameterless constructor. The same is true for subclass objects.

3. Copy construction of derived classes

3.1 format

Derived class::Derived class(const Derived class& another)
	:Base class(another),New member of derived class(another.new blood)
{
}

3.2 code examples

Parent class
student.h

class Student
{
public:
	Student(string sn,int n,char s);
	Student(const Student & another);
	~Student();
	void dis();
private:
	string name;
	int num;
	char sex;
};

student.cpp

Student::Student(string sn, int n, char s)
	:name(sn),num(n),sex(s)
{
}
Student::~Student()
{
}
void Student:: dis()
{
	cout<<name<<endl;
	cout<<num<<endl;
	cout<<sex<<endl;
}
Student::Student(const Student & another)
{
	name = another.name;
	num = another.num;
	sex = another.sex;
}

Subclass
graduate.h

class Graduate:public Student
{
public:
	Graduate(string sn,int in,char cs,float fs);
	~Graduate();
	Graduate(const Graduate & another);
	void dump()
	{
		dis();
		cout<<salary<<endl;
	}
private:
	float salary;
};

graduate.cpp

Graduate::Graduate(string sn, int in, char cs, float fs)
	:Student(sn,in,cs),salary(fs)
{
}
Graduate::~Graduate()
{
}
Graduate::Graduate(const Graduate & another)
	:Student(another),salary(another.salary)
{
}

main.cpp

int main()
{
	Graduate g("123",2001,'x',2000);
	g.dump();
	Graduate gg = g;
	gg.dump();
	return 0;
}

3.3 summary

The default copy constructor in the derived class will call the default or self implemented copy constructor in the parent class. If the self implemented copy constructor in the derived class, the copy constructor that calls the parent class must be displayed.

4. Overload of assignment operator of derived class

The assignment operator function is not a constructor, so it can be inherited. The syntax is not as strict as the constructor.

4.1 format

Subclass& Subclass::operator=(const Subclass& another)
{
	if(this == &another)
		return *this; //Prevent self assignment
	Parent class::operator =(another); // Call the assignment operator overload of the parent class
	this->salary = another.salary;//Subclass member initialization
	return * this;
}

4.2 code examples

Base class
student.h

Student & operator=(const Student & another);

student.cpp

Student & Student::operator=(const Student & another)
{
	this->name = another.name;
	this->num = another.num;
	this->sex = another.sex;
	return * this;
}

Derived class
graduate.h

Graduate & operator=(const Graduate & another);

graduate.cpp

Graduate & Graduate::operator=(const Graduate & another)
{
	if(this == &another)
		return *this;
	Student::operator =(another);
	this->salary = another.salary;
	return * this;
}

4.3 summary

The default assignment operator of the derived class overloads the function and calls the default or self implemented function of the parent class. If the derived class is self implemented, there will be no calling behavior, no error (copy difference) and assignment error. To be correct, it needs to display the self implementation function of the calling parent class.

5. Derived friend functions

Because friend functions are not class members, they cannot be inherited. Under certain requirements, you may want the friend functions of derived classes to use the friend functions in the base class. To this end, you can force the pointer or reference of the derived class to the reference or pointer of its base class through type casting, and then use the converted reference or pointer to call the friend function in the base class.

#include <iostream>
using namespace std;
class Student
{
friend ostream &operator<<(ostream & out, Student & stu);
private:
	int a;
	int b;
};
ostream &operator<<(ostream & out, Student & stu)
{
	out<<stu.a<<"--"<<stu.b<<endl;
}
class Graduate:public Student
{
friend ostream &operator<<(ostream & out, Graduate & gra);
private:
	int c;
	int d;
};
ostream &operator<<(ostream & out, Graduate & gra)
{
	out<<(Student&)gra<<endl;
	out<<gra.c<<"**"<<gra.d<<endl;
}
int main()
{
	// Student a;
	// cout<<a<<endl;
	Graduate g;
	cout<<g<<endl;
	return 0;
}

6. Syntax of derived class destructor

The function of the destructor of a derived class is to clean up the object before it dies. The destructor has no type and no parameters. Destructors are executed in the reverse order of constructors.
Deconstruction sequence

Subclass->member->Base class

7. Identification and access of derived class members

7.1 scope discriminator

format

Base class name::member name; Base class name::Member name (parameter table);

If multiple base classes of a derived class have members with the same name, and the derived class adds such members with the same name, in this case * *, the members of the derived class will shadow (hide) the members with the same name of all base classes * *. This requires such a calling method to call a member of the base class with the same name.

#include <iostream>
using namespace std;
class Base
{
public:
	void func(int)
	{
		cout<<"haha"<<endl;
	}
};
class Drive:public Base
{
public:
	void func()
	{
		Base::func(3); //Members of the shadow can be accessed in this way
		cout<<"hehe"<<endl;
	}
};
int main()
{
	Drive d;
	d.func(); // Access derived class members
	d.Base::func(3); //Accessing base class members
	return 0;
}

7.2 summary

Overload: same scope, function with the same name, different parameters (number, type, order);
Hidden: in parent-child classes, identifiers (functions, variables) are the same, regardless of return values, parameters (functions), or declaration types (variables).

Posted by Browzer on Sun, 31 Oct 2021 21:16:04 -0700