继承的详解

简介: 继承的详解

继承基础

继承得好处:减少重复代码
语法:

class 子类 : 继承方式 父类
子类也称为:派生类
父类也称为:基类

eg:

#include
using namespace std;
//公共部分
class BasePage
{
    
public:
    void test()
    {
    
        cout << "java,C++,Python" << endl;
    }
};
//继承
class java : public BasePage
{
    
public:
    void content()
    {
    
        cout << "java学科视频" << endl;
    }
};
int main()
{
    
    java a;
    a.test();
    a.content();
}

继承方式

1.公共继承
2.保护继承
3.私有继承
原理图:
在这里插入图片描述

继承中的对象模型

问题:从父类继承过来的成员,哪些属于子类对象中?
案例分析:

#include
using namespace std;
class base
{
    
public:
    int m_a;
protected:
    int m_b;
private:
    int m_c;
};
class son:public base
{
    
public:
    int m_d;
};
int main()
{
    
    son a;
    cout << sizeof(a) << endl;
}

执行结果:
16
结论:
父类中所有非静态成员属性都会被子类继承下去。
父类中的私有成员属性是被编译器给隐藏了,因此是访问不到的,但确实被继承下去了。

继承中构造和析构顺序

子类继承父类后,当创建子类对象,也会调用父类的构造函数
问题:
父类和子类的构造和析构顺序是谁先谁后?
实例:

#include
using namespace std;
class base
{
    
public:
    base()
    {
    
        cout << "base的构造函数" << endl;
    }
    ~base()
    {
    
        cout << "base的析构函数" << endl;
    }
};
class son:private base
{
    
public:
    son()
    {
    
        cout << "son的构造函数" << endl;
    }
    ~son()
    {
    
        cout << "son的析构函数" << endl;
    }

public:
    int m_d;
};
int main()
{
    
    son a;
}

执行结果:
在这里插入图片描述
结论:
继承中的构造和析构顺序如下:
先构造父类,再构造子类,
先析构子类,再析构父类。

继承同名成员处理方式

问题:当子类与父类出现同名的成员,如何通过子类对象,访问到子类或父类中同名的数据呢?
1.访问子类同名成员,直接访问即可
2.访问父类同名成员,需要加作用域
eg:
1.同名成员属性

#include
using namespace std;
class base
{
    
public:
    int m_a;
    base()
    {
    
        m_a = 100;
    }
};
class son :public base
{
    
public:
    int m_b;
    son()
    {
    
        m_a = 200;
    }
};
int main()
{
    
    son a;
    cout << a.m_a << endl;//访问子类中的成员
    cout << a.base::m_a << endl;//访问父类中的成员
}

2.同名成员函数

#include
using namespace std;
class base
{
    
public:
    void func()
    {
    
        cout << "调用base下的func函数" << endl;
    }
};
class son :public base
{
    
public:
    void func()
    {
    
        cout << "调用son下的func函数" << endl;
    }
    
};
int main()
{
    
    son a;
    a.func();//访问子类中的成员
    a.base::func();//访问父类中的成员
}

注意事项:
如果子类中出现了和父类同名的成员函数,子类的同名函数成员回隐藏掉父类中所有同名成员函数
如果想访问到父类中被隐藏的同名成员函数,需要加作用域。

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

问题:继承中同名的静态成员在子类对象上如何进行访问?
静态成员和非静态成员出现同名,处理方式一致
1.访问子类同名成员,直接访问即可
2.访问父类同名成员,需要加作用域
eg:
1.同名的静态成员属性

#include
using namespace std;
class base
{
    
public:
    static int m_a;
};
int base::m_a = 200;
class son:public base
{
    
public:
    static int m_a;
};
int son::m_a = 100;
int main()
{
    
    son a;
    //1.通过对象访问
    cout << "son下的m_a = " << a.m_a << endl;
    cout << "base下的m_a = " << a.base::m_a << endl;
    //2.通过类名访问
    cout << "son下的m_a = " << son::m_a << endl;
    cout<<"base下的m_a = "<<son::base::m_a<<endl;
    //解析:第一个::代表通过类名的方式访问   第二个::代表访问父类作用域下的m_a
}

2.同名的静态成员函数

#include
using namespace std;
class base
{
    
public:
    static int m_a;
    static void func()
    {
    
        cout << "base" << endl;
    }
};
int base::m_a = 200;
class son:public base
{
    
public:
    static int m_a;
    static void func()
    {
    
        cout << "son" << endl;
    }
};
int son::m_a = 100;
int main()
{
    
    son a;
    //1.通过对象访问
    a.func();
    a.base::func();
    //2.通过类名访问
    son::func();
    son::base::func();
    //解析:第一个::代表通过类名的方式访问   第二个::代表访问父类作用域下的func()
}

注意事项:
如果子类中出现了和父类同名的静态成员函数,子类的同名函数成员回隐藏掉父类中所有同名成员函数
如果想访问到父类中被隐藏的同名静态成员函数,需要加作用域。

多继承语法

C++允许一个类继承多个类
语法:

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

多继承可能会引发父类中有同名成员函数出现,需要加作用域区分
注意:
C++实际开发中不建议用多继承

#include
using namespace std;
class base1
{
    
public:
    int m_a;
    base1()
    {
    
        m_a = 100;
    }
};
class base2
{
    
public:
    int m_b;
    base2()
    {
    
        m_b = 100;
    }
};
class son: public base1,public base2
{
    
public:
    int m_c;
};

菱形继承

菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承两个派生类
这种继承称为菱形继承,或者钻石继承
图示:
在这里插入图片描述
问题:
1.两个派生类都会有基类的数据,会产生二义性
2.子类会继承两份来自动物的数据,其实并不需要
解决方法:
利用虚继承可以解决菱形继承的问题
即:在继承之前加上关键字virtual 变为虚继承
eg:

#include
using namespace std;
class A
{
    
public:
    int m_age;
};
class B:virtual public A{
    };
class C :virtual public A {
    };
class D : public B, public C{
    };
int main()
{
    
    D a;
    a.A::m_age = 1;
    a.B::m_age = 2;
    a.C::m_age = 3;
    cout << a.m_age << endl;
}
相关文章
|
12月前
|
传感器 机器学习/深度学习 人工智能
仿生机器人:自然界灵感的工程应用
【10月更文挑战第14天】仿生机器人作为自然界灵感与工程技术的完美结合,正逐步改变着我们的生活和工作方式。通过深入了解其设计原理、关键技术、应用领域以及未来的发展趋势,我们可以更加清晰地看到仿生机器人在推动科技创新和社会发展中的重要作用。让我们共同期待仿生机器人在未来带来的更多惊喜和变革!
|
监控 Java 应用服务中间件
Springboot框架开发与实用篇之热部署 2024详解
Springboot框架开发与实用篇之热部署 2024详解
207 0
|
Java 关系型数据库 MySQL
😧 SpringBoot(三)
😧 SpringBoot
144 1
|
机器学习/深度学习 人工智能 达摩院
超越感官,沉浸赛场——大型体育赛事云上实战精选-第三章 2022北京冬奥会:百年奥运的黑科技-百年奥运的瞬即美学:凌空之美,分秒凝结—AI编辑部“云智剪”(中)
超越感官,沉浸赛场——大型体育赛事云上实战精选-第三章 2022北京冬奥会:百年奥运的黑科技-百年奥运的瞬即美学:凌空之美,分秒凝结—AI编辑部“云智剪”
314 0
|
存储 弹性计算 容灾
阿里云服务器配置:ECS实例、带宽存储镜像选择及注意事项
阿里云服务器配置:ECS实例、带宽存储镜像选择及注意事项,2023阿里云服务器选购流程更新,选购云服务器有两个入口,一个是选择活动机,只需要选择云服务器地域、系统、带宽即可;另一个是在云服务器页面,自定义选择云服务器配置,这种方式购买云服务器较为复杂,需要选付费方式、地域及可用区、ECS实例规格、镜像、网络、公网IP、安全组等配置,阿里云百科来阿里云服务器购买流程指南2023新版教程:
336 0
Java计算器的简易实现(+-*/)
java计算器的简易实现(+-*/) import java.util.Scanner; /* 写一个计算器 实现加减乘除四个功能 并且能够用循环接收新的数据,通过用户交互实现 写四个方法 + - * / 利用循环加switch进行用户交互 传递操作的两个数 输出结果 */ public class