• <C++>三大特性 继承:你真的get到了吗?


    🛒本文收录于专栏【大战C++】
    📢专栏目的是对于C++的讲解,重点的逐个击破,会持续输出,欢迎免费订阅!!

    ✨再见少年拉满弓,不惧岁月不惧风✨

    在这里插入图片描述


    🔎继承

    有些类与类之间存在特殊的关系,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性,这个时候我们就可以考虑利用继承的技术,减少重复代码

    👌语法&举例

    我们看到很多网站中,都有公共的头部,公共的底部,甚至公共的左侧列表,只有中心内容不同

    继承实现代码如下:

    //公共页面
    class BasePage
    {
    public:
    	void header()
    	{
    		cout << "首页、公开课、登录、注册...(公共头部)" << endl;
    	}
    
    	void footer()
    	{
    		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
    	}
    	void left()
    	{
    		cout << "Java,Python,C++...(公共分类列表)" << endl;
    	}
    
    };
    
    //Java页面
    class Java : public BasePage
    {
    public:
    	void content()
    	{
    		cout << "JAVA学科视频" << endl;
    	}
    };
    //Python页面
    class Python : public BasePage
    {
    public:
    	void content()
    	{
    		cout << "Python学科视频" << endl;
    	}
    };
    //C++页面
    class CPP : public BasePage
    {
    public:
    	void content()
    	{
    		cout << "C++学科视频" << endl;
    	}
    };
    
    void test01()
    {
    	//Java页面
    	cout << "Java下载视频页面如下: " << endl;
    	Java ja;
    	ja.header();
    	ja.footer();
    	ja.left();
    	ja.content();
    	cout << "--------------------" << endl;
    
    	//Python页面
    	cout << "Python下载视频页面如下: " << endl;
    	Python py;
    	py.header();
    	py.footer();
    	py.left();
    	py.content();
    	cout << "--------------------" << endl;
    
    	//C++页面
    	cout << "C++下载视频页面如下: " << endl;
    	CPP cp;
    	cp.header();
    	cp.footer();
    	cp.left();
    	cp.content();
    
    
    }
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    🎁总结:
    对比普通实现中每一个页面中都要有公共部分,继承就可以轻松解决
    继承的好处:可以减少重复的代码

    🔎补充:
    class A : public B;
    A 类称为子类 或 派生类 B 类称为父类 或 基类

    派生类中的成员,包含两大部分: 一类是从基类继承过来的一类是自己增加的成员。 从基类继承过过来的表现其共性,而新增的成员体现了其个性


    🔥继承方式

    继承方式一共有三种

    • 公共继承
    • 保护继承
    • 私有继承

    👌语法

    class 子类 : 继承方式 父类

    👌举例

    class Base1
    {
    public: 
    	int m_A;
    protected:
    	int m_B;
    private:
    	int m_C;
    };
    
    //公共继承
    class Son1 :public Base1
    {
    public:
    	void func()
    	{
    		m_A; //可访问 public权限
    		m_B; //可访问 protected权限
    		//m_C; //不可访问
    	}
    };
    
    void myClass()
    {
    	Son1 s1;
    	s1.m_A; //其他类只能访问到公共权限
    }
    
    //保护继承
    class Base2
    {
    public:
    	int m_A;
    protected:
    	int m_B;
    private:
    	int m_C;
    };
    class Son2:protected Base2
    {
    public:
    	void func()
    	{
    		m_A; //可访问 protected权限
    		m_B; //可访问 protected权限
    		//m_C; //不可访问
    	}
    };
    void myClass2()
    {
    	Son2 s;
    	//s.m_A; //不可访问
    }
    
    //私有继承
    class Base3
    {
    public:
    	int m_A;
    protected:
    	int m_B;
    private:
    	int m_C;
    };
    class Son3:private Base3
    {
    public:
    	void func()
    	{
    		m_A; //可访问 private权限
    		m_B; //可访问 private权限
    		//m_C; //不可访问
    	}
    };
    class GrandSon3 :public Son3
    {
    public:
    	void func()
    	{
    		//Son3是私有继承,所以继承Son3的属性在GrandSon3中都无法访问到
    		//m_A;
    		//m_B;
    		//m_C;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    🔥继承中构造和析构顺序

    子类继承父类后,当创建子类对象,也会调用父类的构造函数

    继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
    代码如下:

    class Base 
    {
    public:
    	Base()
    	{
    		cout << "Base构造函数!" << endl;
    	}
    	~Base()
    	{
    		cout << "Base析构函数!" << endl;
    	}
    };
    
    class Son : public Base
    {
    public:
    	Son()
    	{
    		cout << "Son构造函数!" << endl;
    	}
    	~Son()
    	{
    		cout << "Son析构函数!" << endl;
    	}
    
    };
    
    
    void test01()
    {
    	//继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反
    	Son s;
    }
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    🔥继承同名成员处理方式

    • 访问子类同名成员 直接访问即可
    • 访问父类同名成员 需要加作用域

    代码如下:

    class Base {
    public:
    	Base()
    	{
    		m_A = 100;
    	}
    
    	void func()
    	{
    		cout << "Base - func()调用" << endl;
    	}
    
    	void func(int a)
    	{
    		cout << "Base - func(int a)调用" << endl;
    	}
    
    public:
    	int m_A;
    };
    
    
    class Son : public Base {
    public:
    	Son()
    	{
    		m_A = 200;
    	}
    
    	//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
    	//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
    	void func()
    	{
    		cout << "Son - func()调用" << endl;
    	}
    public:
    	int m_A;
    };
    
    void test01()
    {
    	Son s;
    
    	cout << "Son下的m_A = " << s.m_A << endl;
    	cout << "Base下的m_A = " << s.Base::m_A << endl;
    
    	s.func();
    	s.Base::func();
    	s.Base::func(10);
    
    }
    int main() {
    
    	test01();
    
    	system("pause");
    	return EXIT_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    🔎补充:

    1. 子类对象可以直接访问到子类中同名成员
    2. 子类对象加作用域可以访问到父类同名成员
    3. 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数

    👌继承同名静态成员处理方式

    静态成员和非静态成员出现同名,处理方式一致

    • 访问子类同名成员 直接访问即可
    • 访问父类同名成员 需要加作用域

    举例代码如下:

    class Base {
    public:
    	static void func()
    	{
    		cout << "Base - static void func()" << endl;
    	}
    	static void func(int a)
    	{
    		cout << "Base - static void func(int a)" << endl;
    	}
    
    	static int m_A;
    };
    
    int Base::m_A = 100;
    
    class Son : public Base {
    public:
    	static void func()
    	{
    		cout << "Son - static void func()" << endl;
    	}
    	static int m_A;
    };
    
    int Son::m_A = 200;
    
    //同名成员属性
    void test01()
    {
    	//通过对象访问
    	cout << "通过对象访问: " << endl;
    	Son s;
    	cout << "Son  下 m_A = " << s.m_A << endl;
    	cout << "Base 下 m_A = " << s.Base::m_A << endl;
    
    	//通过类名访问
    	cout << "通过类名访问: " << endl;
    	cout << "Son  下 m_A = " << Son::m_A << endl;
    	cout << "Base 下 m_A = " << Son::Base::m_A << endl;
    }
    
    //同名成员函数
    void test02()
    {
    	//通过对象访问
    	cout << "通过对象访问: " << endl;
    	Son s;
    	s.func();
    	s.Base::func();
    
    	cout << "通过类名访问: " << endl;
    	Son::func();
    	Son::Base::func();
    	//出现同名,子类会隐藏掉父类中所有同名成员函数,需要加作作用域访问
    	Son::Base::func(100);
    }
    int main() {
    
    	//test01();
    	test02();
    
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    🔥多继承

    class 子类 :继承方式 父类1 , 继承方式 父类2...

    多继承可能会引发父类中有同名成员出现,需要加作用域区分

    class Base1 {
    public:
    	Base1()
    	{
    		m_A = 100;
    	}
    public:
    	int m_A;
    };
    
    class Base2 {
    public:
    	Base2()
    	{
    		m_A = 200;  //开始是m_B 不会出问题,但是改为mA就会出现不明确
    	}
    public:
    	int m_A;
    };
    
    //语法:class 子类:继承方式 父类1 ,继承方式 父类2 
    class Son : public Base2, public Base1 
    {
    public:
    	Son()
    	{
    		m_C = 300;
    		m_D = 400;
    	}
    public:
    	int m_C;
    	int m_D;
    };
    
    
    //多继承容易产生成员同名的情况
    //通过使用类名作用域可以区分调用哪一个基类的成员
    void test01()
    {
    	Son s;
    	cout << "sizeof Son = " << sizeof(s) << endl;
    	cout << s.Base1::m_A << endl;
    	cout << s.Base2::m_A << endl;
    }
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    🔥菱形继承

    概念:

    • 两个派生类继承同一个基类
    • 又有某个类同时继承者两个派生类

    这种继承被称为菱形继承,或者钻石继承

    👌典型的菱形继承案例

    菱形继承问题:

    1. 羊继承了动物的数据,驼同样继承了动物的数据,当草泥马使用数据时,就会产生二义性
    2. 草泥马继承自动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要一份就可以
      在这里插入图片描述

    举例代码如下:

    class Animal
    {
    public:
    	int m_Age;
    };
    
    //继承前加virtual关键字后,变为虚继承
    //此时公共的父类Animal称为虚基类
    class Sheep : virtual public Animal {};
    class Tuo   : virtual public Animal {};
    class SheepTuo : public Sheep, public Tuo {};
    
    void test01()
    {
    	SheepTuo st;
    	st.Sheep::m_Age = 100;
    	st.Tuo::m_Age = 200;
    
    	cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
    	cout << "st.Tuo::m_Age = " <<  st.Tuo::m_Age << endl;
    	cout << "st.m_Age = " << st.m_Age << endl;
    }
    
    
    int main() {
    
    	test01();
    
    	system("pause");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    最近太烂了~ 怎么办~

  • 相关阅读:
    戴尔R730服务器设置管理IP(iDRAC)和安装系统
    10月21日绿健简报,星期五,农历九月廿六
    如何阅读论文?
    谁说程序员不懂浪漫,表白代码来啦~
    接口自动化测试实战之接口框架修改与动态参数化与数据伪造
    高忆管理:军工板块走高,奥普光电涨停,恒宇信通等大涨
    JSON 提取器
    mysql [Err] 1118 - Row size too large (> 8126).
    猿创征文|HCIE-Security Day56:入侵防御技术
    为什么STM32的HAL库那么难用?
  • 原文地址:https://blog.csdn.net/m0_64996150/article/details/125586232