第十一章 类和对象——第6节 继承

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 Apublicprotected不可访问
子类B进行保护继承 class B:protected Aprotectedprotected不可访问
子类B进行私有继承 class B:private Aprivateprivate不可访问
  • 公共继承

    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继承中的对象模型.cpp

    class 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对成员进行访问)
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值