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的值了

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣--字符串58.最后一个单词的长度

思路分析 初始化变量: num 用于记录当前单词的长度。before 用于记录上一个单词的长度。 遍历字符串: 如果字符不是空格&#xff0c;增加 num 计数。如果字符是空格&#xff0c;检查 num 是否为 0&#xff1a; 如果 num 为 0&#xff0c;说明之前没有记录到单词&#xff0c;所以…

嵌入式学习——3——UDP TFTP简易文件传输

tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再支持 TFTP通信…

Qt学习记录(14)线程

前言&#xff1a; 我的臀部已经翘到可以顶起一屁股债了 为什么要使用线程 什么时候用线程 复杂的数据处理 头文件.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer>//定时器头文件QT_BEGIN_NAMESPACE namespace Ui { class Widget; }…

Python+Flask+Pandas怎样实现任意时间范围的对比数据报表

话不多说,有图有源码: 1.上图 2.因为是低代码的,只能发重要有用的代码片段了 实现思路:1)获取指定时间范围内的数据:2)df合并 #----------年份替换----------------for syear in range(int(byear),int(eyear)1):start_datestr(syear)strbdate[4:]end_datestr(syear)stredate…

【大数据】MapReduce JAVA API编程实践及适用场景介绍

目录 1.前言 2.mapreduce编程示例 3.MapReduce适用场景 1.前言 本文是作者大数据系列专栏的其中一篇&#xff0c;前文我们依次聊了大数据的概论、分布式文件系统、分布式数据库、以及计算引擎mapreduce核心概念以及工作原理。 书接上文&#xff0c;本文将会继续聊一下mapr…

光源亮度检测应用笔记

光源亮度检测应用笔记 光电检测应用光电二极管等效模型和基本参数连接并联电阻&#xff08;RJ&#xff09;串联电阻&#xff08;RS&#xff09;结电容&#xff08;CJ&#xff09;暗电流&#xff08;ID&#xff09; 光电二极管电流-电压转换器无源光电二极管电流-电压转换器有源…

C++ Primer 第五版 第十三章 拷贝控制

当定义一个类时&#xff0c;我们显式地或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么。一个类通过定义五种特殊的成员函数来控制这些操作&#xff0c;包括&#xff1a;拷贝构造函数&#xff08;copy constructor&#xff09;、拷贝赋值运算符&#xff08;copy-ass…

柯桥职场人出差必备的商务口语-职场差旅口语提问篇

May I reconfirm my flight? 我可以确认我的班机15857575376吗&#xff1f; Where can I make a reservation? 我到哪里可以预订&#xff1f; Do I have to make a reconfirmation? 我还要再确认吗&#xff1f; Is there any discount for the USA Railpass? 火车通行…

node.js —— 解读http模块

目录 http模块&#xff1a; http模块的引入&#xff1a; 创建web服务器的基本步骤&#xff1a; web服务器的一些基本属性&#xff1a; 上述知识汇总案例&#xff1a; http模块&#xff1a; http模块的引入&#xff1a; const http require (http) 创建web服务器的基本步骤…

探索未来,与移动云共舞

探索未来&#xff0c;与移动云共舞 在数字化飞速发展的今天&#xff0c;云计算已经成为企业、政府乃至个人用户不可或缺的一部分。而在众多云服务提供商中&#xff0c;移动云凭借其独特的优势&#xff0c;为用户带来前所未有的体验。接下来&#xff0c;让我们一起走进移动云的世…

LeetCode题练习与总结:从中序与后序遍历序列构造二叉树--106

一、题目描述 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出…

等保三级云防火墙正版--免费部署满足要求

正版授权内部部署配置授权免费 1、超时退出 2、病毒防护 3、防火墙策略 4、密码复杂度和登录失败处理 5、特征库 点赞关注 私信获取 获取授权 Q 8-5-0-3-4-7-3-3-5

MCU复位电路

【单片机复位电路&#xff0c;巧妙的RC无处不在。】https://www.bilibili.com/video/BV1XW4y1571r?vd_source3cc3c07b09206097d0d8b0aefdf07958 左侧的RESET引脚正常情况下是低电平&#xff0c;是高电平复位&#xff1b;右侧的RESET引脚正常情况下是高电平&#xff0c;是低电…

【电源专题】什么是局部放电(Partial Discharge)

什么是局部放电? 当电压施加在含有两个以上绝缘材料的绝缘物体时,有一个绝缘材料发生放电且至少仍有一个绝缘材料维持正常的绝缘状态,此放电现象称之为局部放电(Partial Discharge)。 举例来说,当待测物的绝缘材料中存在异常气隙,因为空气的介电系数比绝缘材料低以及空气的…

家政服务,让您的家更温馨

家&#xff0c;是我们生活的港湾&#xff0c;也是我们心灵的归宿。在这个快节奏的时代&#xff0c;每个人都在为了生活而奔波。然而&#xff0c;家务琐事却常常成为我们忙碌生活中的绊脚石。为了解决这个问题&#xff0c;家政行业应运而生&#xff0c;为您的生活带来便利与舒适…

vite搭建React+ts+eslint+prettier

一、vite搭建ts模板 npm create vitelatest 项目名 -- --template react-ts//进入到项目文件夹 npm inpm run dev 初始化完成后已经配置好eslint src下一般只留下 初始化git仓库(可选) git init . 二、配置prettier npm i prettier eslint-config-prettier eslint-plugi…

【论文速读】GPT-1:Improving Language Understanding by Generative Pre-Training

摘要 自然语言理解包括广泛的不同的任务&#xff0c;如文本隐含、问题回答、语义相似性评估和文档分类。虽然大量的未标记文本语料库非常丰富&#xff0c;但用于学习这些特定任务的标记数据非常稀缺&#xff0c;这使得经过区别训练的模型要充分执行任务具有挑战性。我们证明&a…

Ubuntu(22.04)不能上网解决办法

想必大家可能在别的贴子看到用以下指令的方法&#xff0c;但是在22版本的ubuntu是行不通的&#xff0c;问题在于22版本中网络管理器的名字压根不是network-manager&#xff0c;而是 NetworkManager. sudo service network-manager stop sudo rm /var/lib/NetworkManager/Netw…

短剧APP开发,短剧行业发展下的财富密码

今年以来&#xff0c;短剧市场展现出了繁荣发展的态势&#xff0c;成为了一个风口赛道。 短剧具有不拖沓、时长短、剧情紧凑等优势&#xff0c;顺应了当代人的生活&#xff0c;是当代人的“电子榨菜”。 短剧的快速发展同时也带动了新业态新模式的发展&#xff0c;短剧APP就是…

ClickHouse vs. Elasticsearch: 计数聚合的工作原理

本文字数&#xff1a;7875&#xff1b;估计阅读时间&#xff1a;20 分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 介绍 在另一篇博客文章中&#xff0c;我们对 ClickHouse 和 Elasticsearch 在大规模数据分析和可观测性用例中的性能进行了比较&#xff0c;特别是对…