C++面向对象的第二大特性:继承

1.继承的介绍

首先容我先向大家举一个列子:

我这里定义了一个Person的类

class Person
{
protected:
    string name;
    int age;
    string address;

};

在这个基础上,我要定义一个关于Student  ,  Worker 的类

由于Student Worker都具有Person类中的成员变量 , 为了实现类的复用,由此引出继承

继承的概念:

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用

上一段代码帮助大家理解:

class Person
{
protected:
    string name;
    int age;
    string address;

};
// 学生这个类继承Person这个类中的成员变量与成员函数
class Student : public Person
{
protected:
    string stuid;
};

 继承的格式:

class 派生类的名字 : 继承方式 基类的名字

继承后的子类成员访问权限:

 注意事项1:父类的private成员在派生类中无论以什么方式继承都是不可见的

这里的不可见指的是派生类对象不管在类里面还是类外面都是不可访问的

用一段代码帮助大家理解

#include<iostream>
#include<string>
using namespace std;
class Person
{
protected:
    string name;
    int age;
private:
    string address;

};
class Student : public Person
{
    void print()
    {
        cout << name << age << address << stuid << endl;// 不能使用address
    }
protected:
    string stuid;
};
int main()
{
    Student s;
    s.address = "faf";不能通过s去访问address
}

2.基类的私有成员在子类都是不可见的,基类的其它成员在子类的访问方式  = min(成员在基类的访问限定符,继承方式), public > protected > private

#include<iostream>
#include<string>
using namespace std;
class A
{
public:
    string name;
protected:
    int age;
private:
    string address;
};
class B : public A
{
    // A中的name在B中的访问是public-> 类里面可以访问 , 类外面也可以访问
    // A中的age在B中的访问是protected -> 类里面可以访问 ,类外面不可以访问
public:
    void print()
    {
        cout << age << " " << name << " " << endl;
    }
};
int main()
{
    B s;
    s.name = "fdadfa";
    // s.age = 18; // 这个方式是错的
    return 0;
}

3. struct 默然的继承方式和访问限定符都是公有的

    class  默然的继承方式和访问限定符都是私有的

2.切割(切片)

前提:用public继承

原则:子类可以赋值给父类,父类不可以给子类

#include<iostream>
#include<string>
using namespace std;
class A
{
public:
    string name;
protected:
    int age;
private:
    string address;
};
class B : public A
{
    
public:
    void print()
    {
        cout << age << " " << name << " " << endl;
    }
};
int main()
{
    B s;
    A t = s;// 子类可以给父类
 //   B c = t; 父类不可以给子类
    return 0;
}

注意:切割要满足赋值兼容 (不会产生临时变量)

#include<iostream>
using namespace std;
class Person
{
public:
    string name = "fafafa";
    int age = 19;
    string address = "dfdadfadaf";

};
class Student : public Person
{
public:
    void print()
    {
        cout << name << " " << age << " " << address << " " << stuid << endl;
    }
protected:
    string stuid = "121231";
};
int main()
{
    Student t;
    Person& tmp = t;
    tmp.age = 29;
    tmp.name = "aaaaaaaaaa";
    t.print();
}

    

tmp是子类中对父类内容的引用,因此对tmp的改变可以影响子类中的内容

3.继承中的作用域

1.在继承体系中基类和派生类都有独立的作用域

2.子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏(重定义)

3.只需要函数名相同就构成隐蔽

#include<iostream>
using namespace std;
class A
{
public:
    void print()
    {
        cout << num << endl;
    }
    int num = 1;
};
class B : public A
{
public:
    int num = 0;
    void print()
    {
        cout << num << endl;

    }
};
int main()
{
    B s;
    s.print();
    return 0;

}

4.子类的默认成员构造函数

        1.构造函数

子类的成员变量可以分为 内置类型 , 自定义类型 , 父类成员变量

原则处理:内置类型不做处理 , 自定义类型调用它的构造函数 , 父类成员变量调用父类的构造函数

#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}

protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}

    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

 2.拷贝构造函数

原则处理:内置类型浅拷贝 , 自定义类型调用它的拷贝构造函数 , 父类成员变量调用父类的拷贝构造函数


#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}
    Person(const Person& s)
        : name(s.name), age(s.age), address(s.address)
    {}
    Person& operator=(const Person& s)
    {
        name = s.name;
        age = s.age;
        address = s.address;
        return *this;
    }
protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}
    Student(const Student& s)
        : Person(s), stuid(s.stuid) {}
    Student& operator=(const Student& s)
    {
        Person::operator=(s);
        stuid = s.stuid;
    }
    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

3.复制重载

 原则处理:内置类型浅拷贝 , 自定义类型调用它的复制重载函数 , 父类成员变量调用父类的复制重载函数

4.析构函数

注意:析构函数名在编译时会被统一命名成destructor

先析构子 , 再析构父

父类的析构函数会自动调用的

#include<iostream>
#include<string>
using namespace std;
class Person
{
public:
    Person(string _name, int _age, string _address)
        :name(_name), age(_age), address(_address)
    {}
    Person(const Person& s)
        : name(s.name), age(s.age), address(s.address)
    {}
    Person& operator=(const Person& s)
    {
        name = s.name;
        age = s.age;
        address = s.address;
        return *this;
    }
    ~Person()
    {
        cout << "~Person" << endl;
    }
protected:
    string name;
    int age;
    string address;

};
class Student : public Person
{
public:
    Student(string _name, int _age, string _address, string _stuid)
        : Person(_name, _age, _address), stuid(_stuid)
    {}
    Student(const Student& s)
        : Person(s), stuid(s.stuid) {}
    Student& operator=(const Student& s)
    {
        Person::operator=(s);
        stuid = s.stuid;
    }
    ~Student()
    {
        cout << "~Student" << endl;
        Person::~Person();
    }
    void print()
    {
        cout << name << age << address << stuid << endl;
    }
protected:
    string stuid;
};
int main()
{
    Student s("fdadfad", 11, "fadfafadfafd", "111111111111");
    return 0;
}

这段代码的结果是: 

原因是:即使我显示的调用Person的析构函数,在Student析构时,仍会自动调用Person的析构函数

5.多继承

多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。

多继承下派生类的定义格式如下:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…

{

<派生类类体>

};

其中,<继承方式1>,<继承方式2>,…是三种继承方式:public、private、protected之一。

#include<iostream>
using namespace std;
class A
{
public:
    int _a;
};
class B : public A

{
public:
    int _b;
};
class C :  public A
{
public:
    int _c;
};
class D : public B, public C
{
public:
    int _d;
};

6.菱形继承 

有上图可知B中继承了两份A的成员变量

导致数据冗余和二义性

解决方式:虚拟继承

#include<iostream>
using namespace std;
class A
{
public:
    int _a;
};
class B : virtual public A

{
public:
    int _b;
};
class C : virtual public A
{
public:
    int _c;
};
class D : public B, public C
{
public:
    int _d;
};
int main()
{
    D s;
    s._a = 1;
    s._b = 2;
    s._c = 3;
    s._d = 4;

    return 0;
}

 底层:

这是s的地址

这是s继承B的内容:

继承的第一个是一个指针 575e9c58(小端)这里的地址后会存一个偏移量

在s的原地址上加上一个偏移量就是_a的值了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/640268.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C语言】指针(三)

目录 一、字符指针 1.1 ❥ 使用场景 1.2 ❥ 有关字符串笔试题 二、数组指针 2.1 ❥ 数组指针变量 2.2 ❥ 数组指针类型 2.3 ❥ 数组指针的初始化 三、数组指针的使用 3.1 ❥ 二维数组和数组名的理解 3.2 ❥ 二维数组传参 四、函数指针 4.1 ❥ 函数的地址 4.2 ❥ 函数…

探索亚马逊云科技技术课程:大模型平台与提示工程的应用与优化

上方图片源自亚马逊云科技【生成式 AI 精英速成计划】技术开发技能课程 前言 学习了亚马逊云科技–技术开发技能课程 本课程分为三个部分&#xff0c;了解如何使用大模型平台、如何训练与部署大模型及生成式AI产品应用与开发&#xff0c;了解各类服务的优势、功能、典型使用案…

借助 CloudFlare 增强站点内容保护防采集

今天在一位站长的帮助下实测了 CloudFlare 增强站点内容保护实现防采集的功能,效果那是杠杠的,如果您的站点原创内容比较多的话,明月强烈建议试试 CloudFlare 这个内容保护,无论是 WordPress 、Typecho 都有非常好的效果,并且几乎没有任何误伤,搜索引擎爬虫蜘蛛更是不会影…

Adobe Animate AN v24.0.2 安装教程 (动画特效设计及合成工具)

Adobe系列软件安装目录 一、Adobe Photoshop PS 25.6.0 安装教程 (最流行的图像设计软件) 二、Adobe Media Encoder ME v24.3.0 安装教程 (视频和音频编码渲染工具) 三、Adobe Premiere Pro v24.3.0 安装教程 (领先的视频编辑软件) 四、Adobe After Effects AE v24.3.0 安装…

深度神经网络教程(个人总结版)

深度神经网络&#xff08;Deep Neural Networks, DNN&#xff09;是机器学习和人工智能的核心技术之一&#xff0c;已经广泛应用于图像识别、自然语言处理、语音识别、自动驾驶等领域。本文将详细介绍深度神经网络的背景、基本原理、架构、训练方法、优化技巧以及常见应用。 一…

vue通过for循环生成input框后双向绑定失效问题

有些时候页面上有太多的表单元素&#xff0c;一个个的写太过繁琐&#xff0c;拿 input 框举例&#xff0c;众多的 input 框&#xff0c;无非就是输入框前的说明和 input 框的 name 属性不一样 <el-form :inline"true" :model"formInline" size"mi…

Linux-笔记 应用编程函数总结

之前一直没做总结&#xff0c;这里总结一下。 一、文件I/O open #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); 例子&#xff1a; int fd; fd open("./test_kondon", O_WRONLY …

文章解读与仿真程序复现思路——电力系统保护与控制EI\CSCD\北大核心《基于改进粒子滤波的锂离子电池剩余寿命预测 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

在使用LabVIEW控制多个串口设备进行数据读取时,读取时间过长

在使用LabVIEW控制多个串口设备进行数据读取时&#xff0c;如果发现数据更新时间超过5秒&#xff0c;可以从以下几个方面进行分析和解决&#xff1a; 1. 串口配置与通信参数 确保每个串口的通信参数&#xff08;波特率、数据位、停止位、校验位等&#xff09;配置正确&#x…

vue的异步操作,钩子函数,和Element组件

目录 使用vue进行异步操作 钩子函数 1.create 2.beforeMount​ 3.mounted​ 4.beforeUpdate​ 5.updated​ 6.beforeUnmount​ 7.unmounted​ Element组件 使用vue进行异步操作 <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…

扫描链接打开小程序配置-谁看谁迷糊

各位你们怎么理解这个规则&#xff1f;如果再多一条数据&#xff0c;和上面一样&#xff0c;只是测试范围为线上版本&#xff0c;又怎么解读&#xff1f; 反正以我对中文的掌握程度&#xff0c;我认为上面的规则是针对体验版的&#xff0c;符合规则的都跳转到体验版。新增的线上…

「51媒体」如何与媒体建立良好关系?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 与媒体建立良好关系对于企业或个人来说都是一项重要的公关活动。 了解媒体&#xff1a;研究媒体和记者的兴趣&#xff0c;提供相关且有价值的信息。 建立联系&#xff1a;通过专业的方式…

FastCopy

目录 背景: 简介&#xff1a; 原理: 下载地址: 工具的使用: 背景: 简介&#xff1a; FastCopy是一款速度非常快的拷贝软件&#xff0c;软件版本为5.7.1 Fastcopy是日本的最快的文件拷贝工具&#xff0c;磁盘间相互拷贝文件是司空见惯的事情&#xff0c;通常情况…

Vue3实战笔记(41)—自己封装一个计时器Hooks

文章目录 前言计时器钩子总结 前言 在Vue项目中&#xff0c;封装一个计时器挂钩&#xff08;Hook&#xff09;是一种实用的技术&#xff0c;它允许你在组件中方便地管理定时任务&#xff0c;如倒计时、计时器等&#xff0c;而无需在每个使用场景重复编写相同的逻辑代码。 计时…

金职优学:分析央国企面试如何通关?

在当今竞争激烈的就业市场中&#xff0c;中央和国有企业&#xff08;以下简称“央国企”&#xff09;的面试机会对求职者来说是非常有吸引力的。这些企业通常拥有稳定的发展前景、良好的薪酬福利和广阔的职业发展空间。但是&#xff0c;要想成功通过央国企的面试&#xff0c;求…

Python列表,元组,集合,字典详解一篇搞懂

目录 介绍 列表(List) 集合(Set) 字典(Dict) 元组(Tuple) 列表 列表定义 ​编辑 列表切片 列表常用方法 append extend ​编辑 insert ​编辑 remove pop ​编辑 clear ​编辑 列表修改元素 sort 升序 倒序 reverse count ​编辑 index 浅拷贝和深拷贝 …

vue contextPath的思考

先说我这边的情况&#xff0c;目前项目都是前后端分离开发的&#xff0c;上线有种部署方式&#xff0c;常见的就是前后端分开部署&#xff0c;这是比较常见的&#xff0c;我这边因客户原因&#xff0c;打包一起进行部署比较简单&#xff0c;交付技术运维部方便后期其他现场部署…

线性规划库PuLP使用教程

Python求解线性规划——PuLP使用教程 简洁是智慧的灵魂&#xff0c;冗长是肤浅的藻饰。——莎士比亚《哈姆雷特》 文章目录 一、说明二、安装 PuLP 库三、线性规划简介3.1 线性规划3.1.1 高考题目描述3.1.2 基本概念 3.2 整数规划3.2.1 题目描述[3]3.2.2 解题思路 四、求解过程…

Python实现数据可视化效果图总结

一、JSON格式 JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据。 JSON本质上是一个带有特定格式的字符串 Json格式 JSON数据格式在Python中可以是字典、又可以是列表中嵌套着字典的格式。 Pyhton数据和Json数据相互转化 二、pyecharts模块 如果想…

NL6621 实现获取天气情况

一、主要完成的工作 1、建立TASK INT32 main(VOID) {/* system Init */SystemInit();OSTaskCreate(TestAppMain, NULL, &sAppStartTaskStack[NST_APP_START_TASK_STK_SIZE -1], NST_APP_TASK_START_PRIO); OSStart();return 1; } 2、application test task VOID TestAp…