(B站黑马C++)继承

C++黑马1.5倍速跟着敲,gpt + 百度 + csdn辅助理解

目录

🔑继承

🌳基本语法

🌳继承方式

🌳继承中的对象模型

🌳构造和析构顺序

🌳同名成员

🌳同名静态成员

🌳多继承语法

🌳菱形继承

🌼总结


🔑继承

继承是面向对象三大特性之一

有些类与类之间存在特殊的关系,例如下图👇


定义这些类时,下级别成员除了拥有上一级的共性,还有自己的特性
这时我们可以利用继承,减少重复代码

🌳基本语法

例如很多网站前端代码中,都有公共的头部,底部和左侧列表,只有中心内容不同
这时继承的意义就体现出来了

语法

class 子类: 继承方式 父类
//eg:
class A: public B
//比如  下面代码中
class Java: public BasePage
class Python: public BasePage
class Cpp: public BasePage

子类  == 派生类

父类  == 基类

子类继承父类的东西 

派生类的成员,包含2部分:
1,从基类(父类)继承过来的
2,自己增加的成员
(基类继承的,表现共性;新增的,表现个性)

先看不用继承的

普通实现

#include<iostream>
using namespace std;

//普通实现

//JAVA
class Java
{
public:
    void header()
    {
        cout<<"首页, 公开课...(公共头部)"<<endl;
    }
    void footer()
    {
        cout<<"帮助中心, 唧唧歪歪(公共底部)"<<endl;
    }
    void left()
    {
        cout<<"Java  Python  C++...(公共分类列表)"<<endl;
    }
    void content()
    {
        cout<<"Java学课视频"<<endl;
    }
};

//Python
class Python
{
public:
    void header()
    {
        cout<<"首页, 公开课...(公共头部)"<<endl;
    }
    void footer()
    {
        cout<<"帮助中心, 唧唧歪歪(公共底部)"<<endl;
    }
    void left()
    {
        cout<<"Java  Python  C++...(公共分类列表)"<<endl;
    }
    void content()
    {
        cout<<"Python学课视频"<<endl;
    }
};

//C++页面
class Cpp
{
public:
    void header()
    {
        cout<<"首页, 公开课...(公共头部)"<<endl;
    }
    void footer()
    {
        cout<<"帮助中心, 唧唧歪歪(公共底部)"<<endl;
    }
    void left()
    {
        cout<<"Java  Python  C++...(公共分类列表)"<<endl;
    }
    void content()
    {
        cout<<"C++学科视频"<<endl;
    }
};

void test01()
{
    Java ja;
    ja.header(), ja.footer(), ja.left(), ja.content();
    cout<<"-----------------------------------"<<endl;
    Python py;
    py.header(), py.footer(), py.left(), py.content();
    cout<<"-----------------------------------"<<endl;
    Cpp cp;
    cp.header(), cp.footer(), cp.left(), cp.content();
    cout<<"-----------------------------------"<<endl;
}


int main()
{
    test01();

    system("pause");
    return 0;
}
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
Java学课视频
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
Python学课视频
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
C++学科视频
-----------------------------------
请按任意键继续. . .

继承实现

关键代码:

class Java: public BasePage
{};
#include<iostream>
using namespace std;

//继承实现
class BasePage //公共页面的类
{
public:
    void header()
    {
        cout<<"首页, 公开课...(公共头部)"<<endl;
    }
    void footer()
    {
        cout<<"帮助中心, 唧唧歪歪(公共底部)"<<endl;
    }
    void left()
    {
        cout<<"Java  Python  C++...(公共分类列表)"<<endl;
    }
};

//Java页面
class Java: public BasePage //写完类的声明后  : public 类名  即可继承
{
public:
    void content()
    {
        cout<<"Java 学课"<<endl;
    }
};

//Python页面
class Python: public BasePage
{
public:
    void content()
    {
        cout<<"Python 学课"<<endl;
    }
};

//C++页面
class Cpp: public BasePage //写完类的声明后  : public 类名  即可继承
{
public:
    void content()
    {
        cout<<"C++ 学课"<<endl;
    }
};

void test01()
{
    Java ja;
    ja.header(), ja.footer(), ja.left(), ja.content();
    cout<<"-----------------------------------"<<endl;
    Python py;
    py.header(), py.footer(), py.left(), py.content();
    cout<<"-----------------------------------"<<endl;
    Cpp cp;
    cp.header(), cp.footer(), cp.left(), cp.content();
    cout<<"-----------------------------------"<<endl;
}


int main()
{
    test01();

    system("pause");
    return 0;
}
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
Java 学课
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
Python 学课
-----------------------------------
首页, 公开课...(公共头部)
帮助中心, 唧唧歪歪(公共底部)
Java  Python  C++...(公共分类列表)
C++ 学课
-----------------------------------
请按任意键继续. . .

继承实现,72行了,比普通实现的92行少了20行

🌳继承方式

继承语法

class 子类: 继承方式 父类

继承方式有3种
1,公共继承
2,保护继承
3,私有继承

#include<iostream>
using namespace std;

//继承方式

//公共继承
class Basel //第1个父类
{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
};

class Son1: public Basel //子类Son继承父类Basel
{
public:
    void func()
    {
        m_A = 10; //父类种公共权限成员 到子类种依然是公共权限
        m_B = 10; //父类  保护权限  到子类还是保护权限
        //m_C = 10; //父类  私有权限  子类无法访问
    }
};

void test01()
{
    Son1 s1;
    s1.m_A = 100;
    //s1.m_B = 100; //保护权限在类外无法访问
}

//保护继承
class Base2 //第2个父类
{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
};

class Son2:protected Base2
{
public:
    void func()
    {
        m_A = 100; //父类  公共  子类中变保护权限
        m_B = 100; //父类  保护  子类中还是保护
        //m_C = 100; //父类中私有  子类无法访问
    }
};

void test02()
{
    Son2 s1;
    //s1.m_A = 1000; //Son2中 m_A为保护, 类外无法访问
    //s1.m_B = 1000; //Son2中 m_B为保护, 类外无法访问
}

//私有继承
class Base3 //第3个父类
{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;
};

class Son3:private Base3
{
public:
    void func()
    {
        m_A = 100; //父类公共  子类中私有
        m_B = 100; //父类保护  子类私有
        //m_C = 100; //父类私有  子类无法访问
    }
};

void test03()
{
    Son3 s1;
    //s1.m_A = 1000; //Son3私有  类外无法访问
    //s1.m_B = 1000; //Son3私有  类外无法访问
}
class GrandSon3:public Son3 //孙子类 继承 儿子类
{
public:
    void func()
    {
        //m_A = 1000; //子类Son3中私有  儿子也无法访问
        //m_B = 1000; //同上
    }
};


int main()
{

    system("pause");
    return 0;
}

🌳继承中的对象模型

#include<iostream>
using namespace std;

//继承中的对象模型
class Base
{
public:
    int m_A;
private:
    int m_C;
protected:
    int m_B;
};

class Son:public Base
{
public:
    int m_D; //父类3个属性  子类本身有1个属性
};

//利用开发人员命令提示工具查看对象模型
//跳转盘符  F:
//跳转文件路径  cd 具体路径下
//查看命名
//c1 /d1 report......

void test01()
{
    //16
    //父类所有非静态成员属性  都会被子类继承下去
    //父类中私有成员属性  被编译器隐藏  无法访问  但被继承了
    cout<<"size of Son = "<<sizeof(Son)<<endl;
}


int main()
{
    test01();

    system("pause");
    return 0;
}

🌳构造和析构顺序

子类继承父类后,创建的子类对象,也会调用父类的构造函数
那么,父类和子类构造和析构顺序,谁先谁后呢?

创建子类时,也会有父类对象的创建 

#include<iostream>
using namespace std;

//继承中 构造和析构 的顺序
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()
{
    //Base b; //父类创建在栈上, test01()结束后会调用析构函数

    //继承中的构造和析构顺序:
    //先构造父类  再构造子类
    //析构顺序与构造顺序相反
    Son s;
}


int main()
{
    test01();


    return 0;
}
Base 构造
Son 构造
Son 析构
Base 析构

🌳同名成员

问题:当子类与父类出现同名成员,如果通过子类对象,访问到子类或父类中同名的数据呢?
1,访问子类同名成员  直接访问
2,访问父类同名成员  加作用域(不论同名属性,还是同名函数,都遵循这一规则)

#include<iostream>
using namespace std;

//继承中同名成员处理
class Base
{
public:
    Base()
    {
        m_A = 100;
    }
    void func()
    {
        cout<<"Base - func()调用"<<endl;
    }
        void func(int a)
    {
        cout<<"Base - func(int a)调用"<<endl;
    }
    int m_A;
};

class Son:public Base
{
public:
    Son()
    {
        m_A = 222;
    }
        void func()
    {
        cout<<"Son - func()调用"<<endl;
    }
    int m_A;
};

//同名成员属性
void test01()
{
    Son s;
    cout<<"Son 的 m_A = "<<s.m_A<<endl;

    //通过子类对象  访问父类同名成员  要加作用域
    cout<<"Base 的 m_A = "<<s.Base::m_A<<endl; //加个父类作用域
}

//同名成员函数
void test02()
{
    Son s;
    s.func(); //直接调用, 调用的是子类中同名函数

    //如何调用父类中同名成员函数?
    s.Base::func();

    //子类出现和父类同名的成员函数 子类同名函数会隐藏掉父类所有同名函数
    //如果想访问父类中被隐藏的同名函数, 请加作用域
    s.Base::func(100);
}


int main()
{
    test01();
    test02();

    return 0;
}
Son 的 m_A = 222
Base 的 m_A = 100
Son - func()调用
Base - func()调用
Base - func(int a)调用

🌳同名静态成员

静态成员和非静态成员,处理方式一致
1,子类,直接访问
2,父类,加作用域

和上一个视频几乎一样,只是静态成员有2种访问方式

#include<iostream>
using namespace std;

//继承中同名静态成员处理方式
class Base
{
public:
    //静态: 编译阶段分配内存  所有对象共享数据  类内声明  类外初始化
    static int m_A;

    static void func()
    {
        cout<<"Base - static void func()"<<endl;
    }

    static void func(int a)
    {
        cout<<"Son - static void func(int a)"<<endl;
    }
};
int Base::m_A = 100; //静态成员  类外初始化


class Son:public Base
{
public:
    static int m_A;

    static void func()
    {
        cout<<"Son - static void func()"<<endl;
    }
};
int Son::m_A = 166;

//同名静态成员属性
void test01()
{
    //静态成员访问方式2种
    //1,通过对象访问
    cout<<"对象访问"<<endl;
    Son s;
    cout<<"Son 下 m_A = "<<s.m_A<<endl;
    cout<<"Base 下 m_A = "<<s.Base::m_A<<endl;

    //2,通过类名访问
    cout<<"类名访问"<<endl;
    cout<<"Son 下 m_A = "<<Son::m_A<<endl;
    //第一个:: 表示通过类名访问
    //第2个 :: 表示访问父类作用域下
    cout<<"Base 下 m_A = "<<Son::Base::m_A<<endl;
}

//同名静态成员函数
void test02()
{
    //1,通过对象访问
    cout<<"通过对象"<<endl;
    Son s;
    s.func();
    s.Base::func();
    cout<<endl;
    //2,通过类名访问
    cout<<"通过类名"<<endl;
    Son::func();
    //Son::类名访问  Base::父类作用域
    Son::Base::func();

    //Son::func(100); //需要加作用域
    Son::Base::func(100);
}

int main()
{
    //test01();
    test02();

    return 0;
}
通过对象
Son - static void func()
Base - static void func()

通过类名
Son - static void func()
Base - static void func()
Son - static void func(int a)

🌳多继承语法

C++允许一个类继承多个类
语法
class 子类 : 继承方式 父类1, 继承方式 父类2...

也就是你可以有多个爹🤭

多继承父类可能存在同名成员,要加作用域

C++实际开发不用多继承

总结:多继承中不同父类出现同名成员,子类调用它们时要加作用域

#include<iostream>
using namespace std;

//多继承语法

class Base1
{
public:

    Base1()
    {
        m_A = 111;
    }
    int m_A;
};

class Base2
{
public:

    Base2()
    {
        m_A = 222;
    }
    int m_A;
};

//子类  继承Base1和Base2
//语法: class 子类:继承方式 父类1, 继承方式 父类2...
class Son:public Base1, public Base2 //是1个冒号,表示继承, 2个冒号是作用域
{
public:
    Son()
    {
        m_C = 333;
        m_D = 444;
    }
    int m_C, m_D;
};

void test01()
{
    Son s;
    cout<<"sizeof Son = "<<sizeof(s)<<endl; //4*4 == 16

    //当不同父类出现同名成员, 加作用域区分
    //cout<<"m_A = "<<s.m_A<<endl;
    cout<<"Base1 ::m_A = "<<s.Base1::m_A<<endl;
    cout<<"Base2 ::m_A = "<<s.Base2::m_A<<endl;
}

int main()
{
    test01();

    return 0;
}
sizeof Son = 16
Base1 ::m_A = 111
Base2 ::m_A = 222

🌳菱形继承

虚继承,可解决菱形继承,但因为是多继承,写项目不建议用,但是面试可能会考到

概念:
两个派生类(子类)继承同一个基类(父类)
又有某个类同时继承两个派生类
成为菱形(钻石)继承

或者

1,羊继承了动物,驼也继承了动物,当草泥马使用数据,会产生二义性
2,草泥马继承自动物的数据,有2份,但是我们只需要1份

关键代码

//羊类
class Sheep:virtual public Animal{};

//驼类
class Tuo:virtual public Animal{};
#include<iostream>
using namespace std;

//动物类
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 = 18;
    st.Tuo::m_Age = 45;

    //菱形继承, 两个父类拥有相同数据, 请加作用域
    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;

    //这份数据, 有1份就行, 但是菱形继承存在2个父类, 资源浪费
}

int main()
{
    test01();

    return 0;
}
st.Sheep::m_Age = 45
st.Tuo::m_Age = 45
st.m_Age = 45

🌼总结

C++的学习,不仅需要学习使用,还要学习底层,难是难一点,为难有所得吧

面试考到的很多语法,黑马C++多少都会说到,学就是了

总好过,看学校的书看不进去

C++黑马课程中,继承是面向对象编程的重要特性,主要分为公共继承、保护继承和私有继承。 ### 公共继承 公共继承是最常见的继承方式。在公共继承中,基类的公有成员在派生类中仍然是公有的,基类的保护成员在派生类中仍然是保护的,而基类的私有成员在派生类中不可直接访问,但会被继承下去。例如: ```cpp class Base { public: int m_A; protected: int m_B; private: int m_C; }; // 公共继承 class Son : public Base { public: int m_D; }; ``` 在这个例子中,`Son` 类通过公共继承从 `Base` 类派生而来。`m_A` 在 `Son` 类中仍然是公有的,`m_B` 仍然是保护的,`m_C` 不可直接访问,但会被继承[^1]。 ### 保护继承 在保护继承中,基类的公有成员和保护成员在派生类中都变成了保护成员,基类的私有成员在派生类中不可直接访问,但会被继承。示例代码如下: ```cpp #include <iostream> using namespace std; class Base { public: int a; protected: int b; private: int c; }; class Driver : protected Base {}; ``` 在这个例子中,`Driver` 类通过保护继承从 `Base` 类派生。`Base` 类的公有成员 `a` 和保护成员 `b` 在 `Driver` 类中都变成了保护成员,`c` 不可直接访问但会被继承[^2]。 ### 私有继承 私有继承中,基类的公有成员和保护成员在派生类中都变成了私有成员,基类的私有成员在派生类中不可直接访问,但会被继承。以下是一个简单示例: ```cpp class Base { public: int m_A; protected: int m_B; private: int m_C; }; class Daughter : private Base {}; ``` 这里 `Daughter` 类通过私有继承从 `Base` 类派生。`Base` 类的公有成员 `m_A` 和保护成员 `m_B` 在 `Daughter` 类中都变成了私有成员,`m_C` 不可直接访问但会被继承
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千帐灯无此声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值