当前位置:网站首页>You can understand the detailed introduction and understanding of inheritance
You can understand the detailed introduction and understanding of inheritance
2022-07-27 01:46:00 【Count of Jiangnan】
Introduction to inheritance
The concept and definition of inheritance
Inheritance is also one of the three characteristics of object-oriented , It is an important means for code reuse , It enables us to expand on the basis of the original class features , Generate new functions , Such a class we become a derived class , The original class is called base class . Inheritance is the same as our previous function reuse , Only this time, the reuse belongs to the design level .
Define format
for example :
class Person {
public:
string _name = "mingzi";
};
class Student :public Person{
public:
void print() {
cout << "name" << _name << endl;
cout << "stid" << _stid << endl;
}
private:
int _stid = 202238;// Student number
};
int main() {
Student stdt;
stdt.print();
}
here Student and Person It becomes a parent-child relationship ,Person It is called base class , Also called a parent class ,Students It is called a derived class , Also called subclass , and public Is called inheritance method . In the above code, we can find that the subclass reuses the members of the parent class , And we can use the member variables of the parent class in the subclass , This is because it uses public Method of inheritance
The inheritance method and access qualifier are the same , Respectively public,protected,private Three
Inherit the change of access mode of base class members
| Members of the class / Inheritance method | public Inherit | protected Inherit | private Inherit |
|---|---|---|---|
| The base class public member | Of a derived class public member | Of a derived class protected member | Of a derived class private member |
| The base class protected member | Of a derived class protected member | Of a derived class protected member | Of a derived class private member |
| The base class private member | Not visible in derived classes | Not visible in derived classes | Not visible in derived classes |
Now we can see that , No matter what type of member or inheritance , The last subclass obtains the one with the smallest range, that is public>protected>private,protect It is called protection member qualifier , Because of inheritance . simply ,private The difference between invisible and , If the derived class is invisible, the subclass cannot use the parent class private member , and private It belongs to the class and can be used , But it cannot be used outside the class . and protected, Of the parent class protected Member subclasses can use , But it cannot be used outside the class .
However, we usually use public
Base class and derived class object assignment conversion
// The same as the previous class
int main(){
Person p;
Student s;
//public Inherit
p=s;// Parent class = Subclass
s=p;// Can not be
Person* ptr=&s;// The pointer
Person& ref=s;// quote
return 0;
}
We assign a subclass object to a parent object / The pointer / The act of quoting is called cutting , Natural behavior , There is no type conversion ( No, const Temporary variable ). Figuratively speaking, there are all members of the parent class in the subclass , Put the superfluous ( It belongs to its own subclass ) The part of is cut off , You can assign values to the parent class in turn from the members in the subclass
Scope in inheritance
Both base and derived classes have independent scopes , When there is a member with the same name in the subclass and parent , Child class members hide parent class members , This situation is called hiding , Also called redefinition
class Person {
public:
string _name = "mingzi";
int _stid=111;
};
class Student :public Person{
public:
void print() {
cout << "name" << _name << endl;
cout << "stid" << _stid << endl;
// If you want to print the parent class, you can use Person::_stid
}
private:
int _stid = 202238;// Student number
};
int main() {
Student stdt;
stdt.print();
}
This will print 202238, Because the member functions of subclasses will call their own member variables first , Hide the parent class ( notes : Try not to duplicate names , But it's different in virtual functions , Later, I will talk about )
class A{
public:
void fun(){
cout << "func" <<endl;
}
};
class B : public A{
public:
void fun(int i){
}
};
int main(){
B b;
b.fun(10);
//b.fun();
b.A::fun();
return 0;
}
here A Classes and B Two properties of class fun Functions form hidden relationships ( As long as the function name is the same , Regardless of the parameters , Is to hide the relationship ), The same function name in inheritance is hidden It is worth noting that , The overload condition is in the same scope .
Default member functions for derived classes
Constructor of subclass —— We don't write , The compiler generates by default , here
1. Inherited parent class members as a whole —— Call the default constructor of the parent class to initialize
2. Own custom type members —— Call its default constructor
3. Own built-in type members —— Don't deal with ( Unless a default value is given in the declaration )
The same is true for the copy constructor of subclasses —— We don't write , The compiler generates by default , here
1、 Inherited parent class members as a whole —— Call the copy construction of the parent class
2、 Own custom type members —— Call its copy construct
3、 Own built-in type members —— Value copy
The same is true for the copy assignment function of subclasses —— We don't write , The compiler generates by default
Subclass destructor – We don't write , The compiler generates by default —— here
1、 Inherited parent class members as a whole – Call the destructor of the parent class
2、 Own custom type members – Call its destructor
3、 Own built-in type members – Don't deal with
The subclass destructor and the parent destructor form a hidden relationship
Because the compiler will do special processing on the destructor name , The destructor names of all classes will be processed into a unified name destructor(). Why should the compiler do this , Polymorphism will talk about
The destructor of the subclass will be executed after the meeting , It will automatically call the destructor of the parent class
class Person
{
public:
Person(const char* name = "peter")
//Person(const char* name) The default constructor is deliberately not given , At this time, the constructor of the subclass is needed to initialize
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)// When passing subclass objects , Here comes the slice
: _name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name; // full name
//int _age;
};
class Student : public Person
{
public:
// We need to implement the subclass constructor ourselves
// Note that the parent class as a whole , Call the constructor of the parent class to initialize
Student(const char* name)
:Person(name)// You can't give it alone _name Assign a value
, _id(id)
, _address(address)
{
}
// When we write a copy constructor
// In general, it is not necessary to write the copy construction of subclasses , Unless the member variables in the subclass have deep and shallow copy problems , Will need it
Student(const Student& s)
:_id(s._id)
, _address(s._address)// It is worth noting that , here address Using a copy of a custom type
// structure , namely string Copy construction of , Because there is no collapse during the decomposition , The description is a deep copy
, Person(s)// Here we can directly pass subclass objects , Reference the parent class , Slices occur here
{
}
// If the copy construct of the child class does not call the copy construct of the parent class ( That is, no Person(s)), A copy construct is also a constructor
// Count , Constructor specifies , If you don't call custom types , That will call its default construction ,( Different from that generated by the compiler )
// When we write the copy assignment function
Student& operator=(const Student& s){
if (this != &s){
_id = s._id;
_address = s._address;
Person::operator=(s); // We show the call = Function of , At this time, both parent and child classes have = overloaded ,
// Constitute a hidden relationship , Otherwise, I will adjust myself , So we need to specify the class domain , section
}
return *this;
}
~Student(){
//Person::~Person();Student And the parent class destruct to form a hidden
// Clean up your resources
} // It will automatically call the destructor of the parent class
private:
int _id;
string _address;
};
int main(){
Student s1(" Zhang San ", 1, " Xi'an City ");
Student s2(s1);
Student s3(" Zhang Si ", 2, " The Beijing municipal ");
s1 = s3; // This will print Person()
// Person(const Person& p)
// Person()
// Person operator=(const Person& p)
// ~Person()
// ~Person()
// ~Person() In the case of subclass decomposition , Sequential parent constructor child constructor destructor parent destructor
}
When the constructor of the parent class is parameterless or a full default constructor is given , The constructor of subclasses can also be the default constructor ( Or not ), To call the default constructor of the parent class . But when the parent class is not the default constructor ( Subclasses cannot use the default constructor ), The constructor of a subclass must be integral to the parent class , To initialize ( Such as :Person(name), Just like the default )
The order of the statements , Is the initialization sequence , So the initialization list of subclasses ( The order in which the list appears is not important , What matters is the order of declarations ), Regardless of parent class Person In which position , The parent class is initialized first
PS: It's rather wordy here , If you don't understand the comments in the code, you can see this .
Copy structure : It is worth noting that , here address It uses a copy structure of custom type , namely string Copy construction of , Because there is no collapse during the decomposition , The description is a deep copy
Inheritance and friends
Display Function is declared as friend , therefore Display Functions can use member variables in classes , But for subclasses , Friends cannot inherit , That is, base class friends cannot access private and protected members of subclasses
class Student;
class Person{
public:
friend void Display(const Person& p, const Student& s);
protected:
string _name; // full name
};
class Student : public Person{
friend void Display(const Person& p, const Student& s);
protected:
int _stuNum; // Student number
};
void Display(const Person& p, const Student& s){
cout << p._name << endl;
cout << s._stuNum << endl;
}
void main(){
Person p;
Student s;
Display(p, s);
}
Inheritance and static members
The base class defines static Static members , Then there is only one such member in the whole inheritance system , Subclasses will not have such static Members of , And we can use the class name to access static members ( Shared by all objects of this class ), Class name :: Variable name
Complex diamond inheritance and diamond virtual inheritance
Single inheritance : When a subclass has only one direct parent class, the whole inheritance relationship is called single inheritance
Multiple inheritance : When a subclass has two or more parent classes, the whole inheritance relationship is called multiple inheritance
diamond inheritance : A special case of multiple inheritance 
class A{
public:
int _a;
};
class B : public A{
public:
int _b;
};
class C : public A{
public:
int _c;
};
class D : public B, public C{
public:
int _d;// Class produces two A Class a Member variables
};
int main(){
D x;
//x._a=0;// Error will be reported at this time , Because there is ambiguity
x.A::_a=0
x.B::_a=0;// This can temporarily solve the problem , You need to display the specified access
In this case, how should we solve such a problem ?
First of all, we know D Class has two _a Member variables of , At this time, we can debug , Use memory to see their data , First of all, let's take d The address of 
We can see d The memory and the monitored address are the same 
We can find it in B Classes and C There is one in each class space _a member
here , We can go through virtual, Virtual inheritance solves ambiguity and data redundancy
//... A little
class B : virtual public A
class C : virtual public A
class D : virtual public B, public C
//.. A little
int main(){
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
d._a = 0;
}
At this time, we check in memory

At this time we can find BC There is no space _a The data of , stay D In the space of class 2, but BC Two addresses are generated in


When we enter two addresses , Found out 14 and 0c Two figures
So what is this ?
In fact, these two values are called offsets ,0x14=20,0x0c=12, At this time, we can calculate ,D Space address -B Space address =20,D Space address -C Space address =12, So we can store the offset , So we can only save 1 Share _a 了 .
02 yes A Storage space of class member variables ,05 yes D The storage space of class member variables
The above two tables are called virtual base tables , We go through B and C Two pointers to a table , Pointers are called virtual base table pointers
But in fact, because we need to add extra pointers to find variables , So the efficiency is reduced , More complicated
B b=d;
B* p=&d;
B& r=&d;// In this way, you can also get _a
summary
In multi inheritance, we can feel C++ Complexity , Therefore, we generally do not recommend designing multiple inheritance , There must be no diamond inheritance
We should give priority to using combinations , Instead of class inheritance , The inner details of the base class in inheritance are visible to subclasses , Inheritance must destroy the encapsulation of the base class , Make the coupling degree of base class and derived class very high
So we try to use combination , Reduce coupling , Combination is called black box reuse , The interior is invisible . Inheritance is called white box reuse
Finally, thank you for seeing here !! If you like, you can like it !
Students who want to know about polymorphism can click here , Simple and easy to understand :【 polymorphic 】 A detailed introduction to polymorphism , Simple and easy to understand
边栏推荐
- Deveco could not resolve com.huawei.ohos:hap:2.4.5.0. error
- MTCNN
- Shell(7)case语句
- Web服务(02)——Web服务器中间件
- Process and planned task management
- 8、 Definition of array
- Regular expression gadget series
- Shell (12) regular expression
- CDC only supports PostgreSQL database to version 12? Is there any plan to support version 14? Does anyone know?
- Web services (02) - Web server middleware
猜你喜欢
随机推荐
标准C库的IO函数
继承的详细介绍与理解,看了就懂
32 Three Musketeers sed
Small project - self connected campus network
Create a daemon
Regular expression gadget series
Paddleocr usage example
22FTP
[SQL injection] error injection
Web Service (04) -- Introduction and construction of lamp +discuz Forum
Shell (6) if judgment
11、 Echo
SSH和NFS服务
C language automatically generates code comments: korofileheader plug-in
Definition of array
Shell(7)case语句
FaceNet
Big model training is difficult to go to the sky? Here comes the efficient and easy-to-use "Li Bai" model library
[mysql] what happens when things are executed concurrently?
29shell函数







![[SQL injection] error injection](/img/89/4809d427e307574cf73af668be3698.png)

