11.6 继承
11.6.1 基本语法
语法:class 子类:继承方式 父类
优点:减少代码重复
class Person {
public:
void AgeInfo() {
cout << "Age : 18" << endl;
}
void SchoolInfo() {
cout << "School : Tsinghua" << endl;
}
void CityInfo() {
cout << "City : Beijing" << endl;
}
};
class Student:public Person { // 继承语法
public:
string m_Name;
Student(string name) :m_Name(name) {};
void NameInfo() {
cout << "Name : " << m_Name << endl;
}
};
void test() { // 实例化两个对象
Student Bob("Bob");
Student John("John");
cout << "Bob的个人信息如下:" << endl;
Bob.AgeInfo();
Bob.CityInfo();
Bob.SchoolInfo();
Bob.NameInfo();
cout << "---------------------------" << endl;
cout << "John的个人信息如下:" << endl;
John.AgeInfo();
John.CityInfo();
John.SchoolInfo();
John.NameInfo();
}
11.6.2 继承方式
继承的基本语法是:class 子类:继承方式 父类
其中继承方式可分为:公共继承、保护继承、私有继承
| 父类A中属性权限 | 公有权限public | 保护权限protected | 私有权限private |
|---|---|---|---|
子类B进行公共继承 class B:public A | public | protected | 不可访问 |
子类B进行保护继承 class B:protected A | protected | protected | 不可访问 |
子类B进行私有继承 class B:private A | private | private | 不可访问 |
-
公共继承
class Person { // 父类 public: string m_city; protected: string m_name; private: int m_age; }; class Student :public Person { // 子类进行公共继承 public: void Modif_member() { m_city = "Beijing"; // 保持公共属性 m_name = "Bob"; // 保持保护属性 // m_age = 18; // 父类的私有属性不可访问 } }; void test1() { // 类外访问类内属性 Student st; cout << st.m_city << endl; // 公共属性 类外可访问 // cout << st.m_name << endl; // 保护属性 类外不可访问 // cout << st.m_age << endl; // 私有属性 类外不可访问 } -
保护继承
class Teacher :protected Person { // 子类进行保护继承 public: void Modif_member() { m_city = "Beijing"; // 改为保护属性 m_name = "Bob"; // 保持保护属性 // m_age = 18; // 父类的私有属性不可访问 } }; void test2() { // 类外访问类内属性 Teacher te; // cout << te.m_city << endl; // 保护属性 类外不可访问 // cout << te.m_name << endl; // 保护属性 类外不可访问 // cout << te.m_age << endl; // 私有属性 类外不可访问 } -
私有继承
class Chair :private Person { // 子类进行私有继承 public: void Modif_member() { m_city = "Beijing"; // 改为私有属性 m_name = "Bob"; // 改为私有属性 // m_age = 18; // 父类的私有属性不可访问 } }; void test3() { // 类外访问类内属性 Chair ch; // cout << ch.m_city << endl; // 私有属性 类外不可访问 // cout << ch.m_name << endl; // 私有属性 类外不可访问 // cout << ch.m_age << endl; // 私有属性 类外不可访问 }
11.6.3 继承中的对象模型
结论:
- 父类中所有非静态成员属性都会被子类继承下去
- 父类中的私有属性是被编译器隐藏了,虽然访问不到但是被继承下来了
class Person { // 父类中包含三个继承方式的int型成员变量
public:
int m_A;
protected:
int m_B;
private:
int m_C;
};
class Student :public Person { // 子类继承父类的基础上,还有自身的一个int成员变量
public:
int m_D;
};
void test() {
cout << "size of Student:" << sizeof(Student) << endl; // sizeof(Student) = 16(int*4 = 4*4 = 16)
}
使用Developer Command Prompt查看类结构的方法
-
电脑中打开
Developer Command Prompt软件 -
cd进入cpp文件夹所在路径cd G:\Cpp_Project\01 HelloWorld -
cl /d1 reportSingleClassLayout类名 类所在cpp文件.cpp查看对应类的结构,例如cl /d1 reportSingleClassLayoutStudent 129继承中的对象模型.cppclass Student size(16): +--- 0 | +--- (base class Person) # 父类名称 0 | | m_A # 从父类继承的属性 4 | | m_B 8 | | m_C | +--- 12 | m_D +---
11.6.4 继承中构造与析构顺序
结论:构造父类 -> 构造子类 -> 析构子类 -> 析构父类
class Person {
public:
Person() {
cout << "父类Person开始构造" << endl;
}
~Person() {
cout << "父类Person开始析构" << endl;
}
};
class Student:public Person {
public:
Student() {
cout << "子类Student开始构造" << endl;
}
~Student() {
cout << "子类Student开始析构" << endl;
}
};
void test() {
Student st;
}
/*********************运行结果************************/
//父类Person开始构造
//子类Student开始构造
//子类Student开始析构
//父类Person开始析构
11.6.5 同名成员处理
同名成员包括同名成员变量和同名成员函数,都遵循以下原则:
-
访问子类同名成员:直接访问
st.m_age = 1; // 访问子类中的同名成员变量 st.set_age(); // 访问子类中的同名成员函数 -
访问父类同名成员:添加作用域
st.Person::m_age = 1; // 访问父类中的同名成员变量 st.Person::set_age(); // 访问父类中的同名成员变量
示例:
class Person {
public:
int m_age;
Person(){
m_age = 100;
}
};
class Student :public Person {
public:
int m_age;
Student() {
m_age = 50;
}
};
void test() {
Student st;
cout << st.m_age << endl;
cout << st.Person::m_age; // 添加作用域
}
注意:只要调用的是父类中的同名函数,就需要添加作用域,因为当父类中成员函数与子类中成员函数同名时,子类的同名成员会隐藏掉父类的所有同名函数。例如下方示例中父类的三个函数都与子类成员函数同名,虽然结构不同由肉眼可区分,但是在调用父类函数时仍需要添加作用域。
class Person{
public:
int set_age(){}
float set_age(){}
int set_age(int age){}
};
class Student:public Person{
public:
int set_age(){}
};
11.6.6 同名静态成员处理
静态同名成员处理时与非静态成员一致:
-
访问子类同名成员:通过对象直接访问
st.m_age = 1; // 访问子类中的同名成员变量 st.set_age(); // 访问子类中的同名成员函数 -
访问父类同名成员:通过对象添加作用域访问
st.Person::m_age = 1; // 访问父类中的同名成员变量 st.Person::set_age(); // 访问父类中的同名成员变量
与非静态成员不同的是, 同名静态成员由于11.2.8节《静态成员》中共享同一内存空间的特点,也可通过类名对其进行访问:
-
访问子类同名成员:通过类名直接访问
Student::m_age = 1; // 访问子类中的同名成员变量 Student::set_age(); // 访问子类中的同名成员函数 -
访问父类同名成员:通过类名添加作用域访问
Student::Person::m_age = 1; // 访问父类中的同名成员变量 Student::Person::set_age(); // 访问父类中的同名成员变量- 第一个
::代表通过子类的类名方式进行访问 - 第二个
::代表访问父类作用域下的成员
示例:
class Person { public: static int m_age; }; int Person::m_age = 100; // 静态成员属性要遵循:类内声明,类外初始化 的原则 class Student :public Person { public: static int m_age; }; int Student::m_age = 50; // 静态成员属性要遵循:类内声明,类外初始化 的原则 void test() { Student st; Person pe; cout << st.m_age << endl; // 通过对象访问子类同名成员属性 cout << Student::m_age << endl; // 通过类名访问子类同名成员属性 cout << pe.m_age << endl; // 通过对象访问父类同名成员属性 cout << Student::Person::m_age << endl; // 通过类名访问父类同名成员属性 } - 第一个
11.6.7 多继承语法
C++允许一个类继承多个父类,但实际开发中不建议这样做,多继承可能引发父类中有同名成员出现,需要加作用域区分
语法:class 子类名:继承方式1 父类名1, 继承方式2 父类名2, ……
11.6.8 菱形继承问题
问题描述:若出现如下所示的继承情况,则称为菱形继承。菱形继承会导致以下问题
- 子类3在访问成员时会产生二义性,系统不知道你要访问的是子类1的还是子类2的
- 子类3从基类会继承两份相同的数据,导致资源浪费
解决方法:使用虚继承的方式解决
语法:class 子类x:virtual 继承方式 虚基类{};
底层原因:通过虚继承方式,子类1、2继承的不再是基类的m_age属性的数据,而是继承了虚基类指针vbptr,该指针指向的是同一个存储虚基类属性数据的地址

class Person { // 父类
public:
int m_age;
};
class Student:virtual public Person{}; // 子类1 进行虚拟继承
class Teacher:virtual public Person{}; // 子类2 进行虚拟继承
class SchoolMember :public Student, public Teacher {}; // 同时继承 子类1 和 子类2
void test() {
SchoolMember sm;
sm.Student::m_age = 100;
sm.Teacher::m_age = 50; // 此时子类1、2的同名成员共享同一内存空间,将100修改为50
cout << sm.Student::m_age << endl; // 50
cout << sm.Teacher::m_age << endl; // 50
cout << sm.m_age << endl; // 50(当进行虚拟继承后,由于m_age共享同一内存,故可以直接使用sm.m_age对成员进行访问)
}

被折叠的 条评论
为什么被折叠?



