Inheritance in C++
Article Directory
-
-
-
- Inheritance in C++
- 1. The concept and definition of inheritance
- 1.1 Inheritance definition
- 1.12 Inheritance Relationships and Access Qualifiers
- 2. Copy conversion of base class and derived class objects
- 3. Scope in inheritance
- 4. Default member functions of derived classes
- 6. **Inheritance and static members**
- **Complex diamond inheritance and diamond virtual inheritance**
- 7. The principle of virtual inheritance to solve data redundancy and ambiguity
-
-
1. The concept and definition of inheritance
Inheritance is an important way to improve the code reuse rate. It allows programmers to add other features and functions on the basis of maintaining the characteristics of the original class . Such classes are called derived classes. Inheritance is the reuse of class design levels .
class Person
{
public:
void Print()
{
cout << "name: " << _name << endl;
cout << "age: " << _age << endl;
}
protected:
string _name = "牡丹";
int _age = 18;
};
class Student :public Person
{
protected:
int _stuid;
};
class Teacher :public Person
{
protected:
int _jobid;
};
int main(void)
{
Student s;
Teacher t;
s.Print();
t.Print();
return 0;
}
The result of the operation is:
Obviously Student和Teacher
there are no functions in it Print()
, why is it still running normally? Because they all inherit Person
the class.
1.1 Inheritance definition
Below we see that Person is the parent class, also known as the base class. Student is a subclass, also known as a derived class.
1.12 Inheritance Relationships and Access Qualifiers
class members/inheritance | public inheritance | protected inheritance | private inheritance |
---|---|---|---|
public members of the base class | public members of derived classes | protected members of derived classes | private members of derived classes |
protected members of the base class | protected members of derived classes | protected members of derived classes | private members of derived classes |
private members of the base class | Not visible (hidden) in derived classes | Not visible (hidden) in derived classes | Not visible (hidden) in derived classes |
Summarize
1. The members of the base class private
are invisible and hidden in the derived class regardless of the inheritance method. Outside the class, they are private
members that cannot be called in the derived class and are hidden.
2. private
Members cannot be accessed in derived classes, but if you want to be inaccessible outside the class, you can use them if they are accessed in derived classes protected
.
3. public > protected > private
The access method of other members of the base class in the subclass == the one with less authority
4. The default inheritance method when using the keyword class is private
, struct
the default inheritance method when using is public
, but it is best to display
write out inheritance
5. In practice, inheritance is generally used , and inheritance publicb
is rarely used , and the use of it is not advocated.protetced/private
protetced/private
Inheritance, because protetced/private
the inherited members can only be used in the class of the derived class, in practice
Extended maintenance is not strong.
2. Copy conversion of base class and derived class objects
-
Objects of derived classes can be assigned to objects of base classes/pointers of base classes/references of base classes . There is a very vivid saying called slicing or cutting. It is to cut and assign the value of the parent class in the derived class.
-
An object of a base class cannot be assigned to a derived class
-
A pointer to a base class can be assigned to a pointer to a derived class by casting. But only when the pointer of the base class points to the derived class object
is safe. Here, if the base class is a polymorphic type, you can use
RTTI
the dynamic_cast of (Run-Time Type Information) toSecurity transitions are performed after identification is performed.
class Person
{
protected:
string _name; // 姓名
string _sex; // 性别
int _age; // 年龄
};
class Student : public Person
{
public:
int _No; // 学号
};
void Test()
{
Student sobj;
// 1.子类对象可以赋值给父类对象/指针/引用
Person pobj = sobj;//Person = Student
Person* pp = &sobj;//Person = Student
Person& rp = sobj;//Person = Student
//2.基类对象不能赋值给派生类对象
sobj = pobj;//Student = Person
// 3.基类的指针可以通过强制类型转换赋值给派生类的指针
pp = &sobj;
Student * ps1 = (Student*)pp; // 这种情况转换时可以的。Student* = (Student*)Person*
ps1->_No = 10;
pp = &pobj;//Person =Person
Student* ps2 = (Student*)pp; // 这种情况转换时虽然可以,但是会存在越界访问的问题
ps2->_No = 10;
}
3. Scope in inheritance
1. In the inheritance system, the base class and the derived class have independent scopes
2. There are members with the same name in the subclass and the parent class. The relationship between the subclass members and the parent class members is called hiding . If you have to access the members of the parent class, you can add an access qualifier to display the access
3. The function only needs to have the same function name to form a hidden function, and the parameters are irrelevant.
4. It is best not to define members with the same name
class Person
{
public:
protected:
string _name="牡丹";
int _num=18;
};
class Student :public Person
{
public:
void Print()
{
cout << "姓名:" << _name << endl;
cout << "学号:" << _num << endl;
cout << "学号:" << Person::_num << endl;
}
protected:
int _num = 520;
};
int main(void)
{
Student s1;
s1.Print();
return 0;
}
operation result:
class Person
{
public:
void Print(int a)
{
cout << "姓名:" << _name << endl;
cout << "学号:" << _num << endl;
}
protected:
string _name="牡丹";
int _num=18;
};
class Student :public Person
{
public:
void Print()
{
Person::Print(1);
cout << "姓名:" << _name << endl;
cout << "学号:" << _num << endl;
cout << "学号:" << Person::_num << endl;
}
protected:
int _num = 520;
};
int main(void)
{
Student s1;
s1.Print();
return 0;
}
What constitutes here is the hiding of the function rather than overloading, because it is not in the same scope
4. Default member functions of derived classes
6 default member functions, the default means that we do not write, the compiler will change us to automatically generate one, then in the derived class, these
How are member functions generated?
1. The constructor of the derived class must call the constructor of the base class to initialize the part of the base class. If the base class does not have a default constructor, it must be called explicitly in the initialization list phase of the derived class constructor.
2. The copy construction of the derived class must call the copy construction of the base class to complete the initialization of the base class.
3. The derived class
operator=
must call the base classoperator=
to complete the copy of the base class.4. The destructor of the derived class will automatically call the destructor of the base class to clean up the members of the base class after being called . Because this ensures that derived classes
The order in which the object first cleans up derived class members and then cleans up base class members.
5. Derived class object initialization calls the base class construction first and then calls the derived class construction.
6. The derived class object destructor cleanup first calls the derived class destructor and then adjusts the base class destructor.
class Person
{
public:
Person(const char* name = "牡丹")
:_name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
:_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;
};
class Student : public Person
{
public:
Student(const char* name, int num)
: Person(name)
, _num(num)
{
cout << "Student()" << endl;
}
Student(const Student& s)
: Person(s)
, _num(s._num)
{
cout << "Student(const Student& s)" << endl;
}
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)
{
Person::operator =(s);
_num = s._num;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
protected:
int _num; //学号
};
void Test()
{
Student s1("jack", 18);
Student s2(s1);
Student s3("rose", 17);
s1 = s3;
}
int main(void)
{
Test();
return 0;
}
This code:
实例化对象s1的时候会先去调用Student的构造函数,然后再Student的构造函数当中显示的调用了父类的构造函数。
实例化对象s2的时候先调用Student的拷贝构造,在拷贝构造的初始化列表当中显示的调用父类的拷贝构造
实例化s3的时候和s1一样
s1赋值给s3的时候先去调用子类的operator=,但是在子类当中会调用父类的operator=
Inheritance and Friends
Friend relationships cannot be inherited , that is to say, base class friends cannot access subclass private and protected members
Display is a friend of the base class Person. If Student also inherits the friendship relationship in Person, then the s._stuNum here is accessible, but the result is not accessible, so the friendship relationship cannot be inherited
6. Inheritance and static members
**If the base class defines a static static member, there is only one such member in the entire inheritance system. ** No matter how many subclasses are derived, there is only one
static member instance
class Person
{
public :
Person () {++ _count ;}
protected :
string _name ; // 姓名
public :
static int _count; // 统计人的个数。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
int _stuNum ; // 学号
};
class Graduate : public Student
{
protected :
string _seminarCourse ; // 研究科目
};
void TestPerson()
{
Student s1 ;
Student s2 ;
Student s3 ;
Graduate s4 ;
cout <<" 人数 :"<< Person ::_count << endl;
Student ::_count = 0;
cout <<" 人数 :"<< Person ::_count << endl;
}
Complex Diamond Inheritance and Diamond Virtual Inheritance
Single inheritance: When a subclass has only one direct parent class, the inheritance relationship is called single inheritance
Multiple inheritance: When a subclass has two or more direct parent classes, the inheritance relationship is called multiple inheritance
Diamond inheritance: Diamond inheritance is a special case of multiple inheritance.
The problem of diamond inheritance: From the following object member model construction, it can be seen that diamond inheritance has data redundancy and ambiguity problems. There will be two copies of the Person member in the Assistant object.
class Person
{
public:
string _name; // 姓名
};
class Student : public Person
{
protected:
int _num; //学号
};
class Teacher : public Person
{
protected:
int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
void Test()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}
Virtual inheritance can solve the ambiguity and data redundancy problems of diamond inheritance.
class Person
{
public:
string _name; // 姓名
};
class Student :virtual public Person
{
protected:
int _num; //学号
};
class Teacher : virtual public Person
{
protected:
int _id; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
void Test()
{
// 这样会有二义性无法明确知道访问的是哪一个
Assistant a;
a._name = "peter";
// 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
a.Student::_name = "xxx";
a.Teacher::_name = "yyy";
}
int main(void)
{
Test();
return 0;
}
In this way, they all point _name
to the same thing _name
.
7. The principle of virtual inheritance to solve data redundancy and ambiguity
It can be seen that the members of virtual inheritance are all placed in the public area, but there are two more addresses here, which look like two pointers
It can be seen that there is a 14
sum here 0c
, the hexadecimal of 14 is 20, and c is 12, which just records the distance from the current class to the public area.