类 —— 继承、多重继承

继承

一个类,继承另一个已有的类。(在一个已存在的类的基础上建立一个新的类,并拥有其特性)
是一个父类(基类)派生出子类(派生类)的过程。
派生类往往是基类的具象化,基类则是派生类的抽象。
基类与派生类是相对的,一个类可能存在又是基类又是派生类的情况。
继承提高了代码的复用性

在实际的使用中,派生类会做出一些与基类的差异化:
● 修改继承来自的基类内容
属性:公有属性直接修改,私有属性通过接口修改
函数:函数隐藏,通过派生类实现一个同名同参数的函数,来隐藏基类的函数。
● 新增派生类的内容

#include <iostream>
using namespace std;// 基类
class Father
{
private:string name = "张";public:void set_name(const string &name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜。" << endl;}
};// 派生类继承基类
class Son:public Father
{
public:void init(){set_name("王");				// 私有属性通过接口修改}void work(){cout << "我是飞行员,我要上天。" << endl;}void game(){cout << "三硝基甲苯。" << endl;}
};int main()
{Son s;cout << s.get_name() << endl; 			// 张s.init();cout << s.get_name() << endl; 			// 王s.work();				// s.game();// 调用基类被隐藏的成员函数s.Father::work();return 0;
}

继承的格式、权限

class 类名:父类名 {};					// 默认权限是 private
class 类名:继承的权限 父类名 {};

在这里插入图片描述
在这里插入图片描述

继承时类中的特殊成员函数不会被继承

构造函数

派生类中的任意一个构造函数,都必须直接或者间接调用基类的一个构造函数。

problem:
#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father(string secret, string fname, float asset):secret(secret), firstname(fname), asset(asset){cout << "A constructor of father class with parameters. " << endl;}
};class Son:public Father
{string secret;
public:void show(){cout << "First name: " << firstname << endl;}};int main()
{// Son s1;  				// 找不到基类的无参构造函数    // error,因为父类只有有参构造,而子类中没有提供 能够调用父类有参构造的构造函数,不能成功创建父类的空间// Son s2("~", "0", 1);		// 找不到匹配的构造函数cout << "Size of father: " << sizeof(Father) << endl;cout << "Size of son: " << sizeof(Son) << endl;return 0;
}

在这里插入图片描述
在这里插入图片描述

solution1:补充基类的无参构造函数
#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father():secret("~"), firstname("w"), asset(1000000) { }Father(string secret, string fname, float asset):secret(secret), firstname(fname), asset(asset){cout << "A constructor of father class with parameters. " << endl;}
};class Son:public Father
{string secret;
public:void show(){cout << "First name: " << firstname << endl;}};int main()
{Son s1;s1.show();// Son s2("~", "0", 1);		// 找不到匹配的构造函数cout << "Size of father: " << sizeof(Father) << endl;cout << "Size of son: " << sizeof(Son) << endl;return 0;
}

在这里插入图片描述

solution2:透传构造

需要 在子类构造函数的初始化列表中 显性调用父类的构造函数
当父类中只有有参构造,子类在创建类对象时,必须手动调用父类的构造函数。
在这里插入图片描述

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father(string fname, float asset):firstname(fname), asset(asset){cout << "A constructor of father class with parameters. " << endl;}
};class Son:public Father
{string secret;
public:						Son():Father("default string", 120000)//, secret("0")		// 这里使用具体的值{ }// Father(fname, asset) 和 secret(secret) 可以交换,但有警告Son(string fname, float asset, string secret):Father(fname, asset), secret(secret){}void show(){cout << "First name: " << firstname << endl;cout << "Asset: " << asset << endl;cout << "Secret of the son: " << secret << endl;}
};int main()
{Son s1("Xing", 120000, "secret1");s1.show();Son s2;s2.show();return 0;
}

在这里插入图片描述

solution3:继承构造(C++ 11 支持)

C++支持 不用在子类中再写一遍父类的构造函数 ——

using Father::Father; 		// 在子类中使用父类的构造函数

直接使用继承构造的方式,不能对子类成员初始化
继承构造本质上并不是把父类中的构造函数继承给子类,编译器自动根据父类中构造函数的格式,提供出派生的构造函数(个数、参数都和父类中的构造函数一致),主要还是通过透传构造创建父类的空间。
在这里插入图片描述

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father():secret("~"), firstname("w"), asset(1000000){cout << "A constructor of father class with no parameters. " << endl;}Father(float asset):asset(asset){cout << "A constructor of father class with only one parameter. " << endl;}Father(string fname, float asset):firstname(fname), asset(asset){cout << "A constructor of father class with two parameters. " << endl;}Father(Father &other):firstname(other.firstname), asset(other.asset)	// 拷贝构造{cout << "Duplicator_constructor of father class. " << endl;}
};class Son:public Father
{string secret;using Father::asset;        // 把父类中公有继承下来的 asset 成员,在子类中改成私有权限using Father::Father;public:void show(){cout << "First name: " << firstname << endl;cout << "Asset: " << asset << endl;cout << "Secret of the son: " << secret << endl;}
};int main()
{Son s0;s0.show();Son s1(120000);s1.show();Son s2("Xing", 120000);s2.show();Son s3 = s2;s3.show();return 0;
}

在这里插入图片描述

solution4:委托构造

一个类的构造函数可以调用这个类中的另一个构造函数,但是要避免循环委托
委托构造的性能低于透传构造,但是代码维护性更好,因为通常一个类中构造函数都会委托给能力最强(参数最多)的构造函数,代码重构时,只需要更改这个参数最多的构造函数即可。

只有一个类

并不直接通过无参构造实例化对象,而是无参构造委托有参构造,从而实例化对象。
在这里插入图片描述

#include <iostream>
using namespace std;class Son
{string secret;
public:Son():Son("secret0"){cout << "A constructor of child class without parameters. " << endl;}Son(string secret):secret(secret){cout << "A constructor of child class with parameter(s). " << endl;}void show(){cout << "Secret of the son: " << secret << endl;}
};int main()
{Son s0;s0.show();Son s1("secret1");s1.show();return 0;
}

在这里插入图片描述

父子类的继承

在这里插入图片描述

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father(string fname, float asset):firstname(fname), asset(asset){cout << "A constructor of father class with two parameters. " << endl;}Father(float asset):asset(asset){cout << "A constructor of father class with only one parameter. " << endl;}
};class Son:public Father
{string secret;public:Son():Son("secret0"){cout << "A constructor of child class without parameters. " << endl;}Son(string secret):Father("Xing", 120000), secret(secret){cout << "A constructor of child class with parameter(s). " << endl;}void show(){cout << "First name: " << firstname << endl;cout << "Asset: " << asset << endl;cout << "Secret of the son: " << secret << endl;}
};int main()
{Son s0;s0.show();return 0;
}

在这里插入图片描述

拷贝构造函数

需要在初始化列表中显性调用父类的拷贝构造,传 other 对象到父类的拷贝构造中。

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father(string fname, float asset):firstname(fname), asset(asset){cout << "A constructor of father class with two parameters. " << endl;}Father(float asset):asset(asset){cout << "A constructor of father class with only one parameter. " << endl;}Father(Father &other):firstname(other.firstname), asset(other.asset){cout << "Duplicator_constructor of father class. " << endl;}
};class Son:public Father
{string secret;public:Son(string fname, float asset, string secret):Father(fname, asset), secret(secret){}Son(Son &other):Father(other), secret(other.secret){cout << "Duplicator_constructor of child class. " << endl;}void show(){cout << "First name: " << firstname << endl;cout << "Asset: " << asset << endl;cout << "Secret of the son: " << secret << endl;}
};int main()
{Son s1("Xing", 120000, "secret1");s1.show();Son s2 = s1;s2.show();return 0;
}

在这里插入图片描述

继承时构造和析构的时机

子类在继承父类时,会先把父类中的成员保留一份,再来创建子类自己的成员。
父类先构造,子类后构造。子类先析构,父类后析构。

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float asset;Father(string fname, float asset):firstname(fname), asset(asset){cout << "A constructor of father class with two parameters. " << endl;}Father(float asset):asset(asset){cout << "A constructor of father class with only one parameter. " << endl;}~Father()				// 注意这里没有用虚析构函数{cout << "Destructor of father class. " << endl;}
};class Son:public Father
{string secret;
public:Son():Father("default string", 120000)          // 这里使用具体的值{cout << "A constructor of child class with no parameters. " << endl;}Son(string fname, float asset, string secret):Father(fname, asset), secret(secret){cout << "A constructor of child class with parameters. " << endl;}~Son(){cout << "Destructor of child class. " << endl;}
};int main()
{Son *s = new Son;delete s;s = nullptr;cout << endl;Son *ss = new Son("z", 1200000, "0");delete ss;ss = nullptr;cout << endl;Father *sss = new Son();delete sss;sss = nullptr;cout << endl;Father *ssss = new Son("z", 1200000, "0");delete ssss;ssss = nullptr;cout << endl;return 0;
}

在这里插入图片描述
在这里插入图片描述

当父子类中存在同名成员

访问时不会发生冲突,默认访问子类的成员变量。

#include <iostream>
using namespace std;class Father
{string secret;
public:string firstname;float *asset;Father():asset(new float){cout << "A constructor of father class without parameters. " << endl;}~Father(){delete asset;cout << "Destructor of father class. " << endl;}
};class Son:public Father
{string secret;public:float *asset;Son():asset(new float){cout << "A constructor of child class without parameters. " << endl;}~Son(){delete asset;cout << "Destructor of child class. " << endl;}};int main()
{Son *m = new Son;*(m->asset) = 140000;cout << "*(m->asset): " << *(m->asset) << endl;cout << "*(m->Father::asset): " << *(m->Father::asset) << endl;delete m;m = nullptr;return 0;
}

在这里插入图片描述

多重继承

一个子类,继承自多个基类。

格式

class 类名:继承权限 父类名, 继承权限 父类名, …
{
};

1、当多个父类中包含同名成员

多个父类中包含同名成员,通过 域限定符 访问指定的父类中成员。

#include <iostream>
using namespace std;class Father
{string secret;
public:void act_1(){cout << "Earn money. " << endl;}
};class Son:public Father
{string secret;public:void act_1(){cout << "Save money. " << endl;}void act_2(){cout << "Inherit money. " << endl;}
};class Grandchild:public Father, public Son
{
};int main()
{Son s;s.act_1();s.Father::act_1();Grandchild g;g.act_2();g.Son::act_2();return 0;
}

在这里插入图片描述

2、菱形继承(钻石继承)

     A                ------>		公共基类/   \B     C             ------>		中间子类\   /D                ------>		汇集子类

汇集子类中,会包含多份公共基类中的内容。

Problems ——>

1、会发生二义性的问题(同一个变量或者函数,可以通过两种方法访问)
2、如果公共基类过大,会造成汇集子类中的代码 膨胀 / 冗余。

#include <iostream>
using namespace std;class A
{
public:int a;
};class B:public A
{
};class C:public A
{
};class D:public C, public B
{
};int main()
{D d0;d0.C::a = 100;cout << "In C: " << d0.C::a << endl;		// 100d0.B::a = 90;   				// 可以直接通过中间子类访问,直接访问 B 中的 a成员cout << "In B: " << d0.B::a << endl;		// 90// d0.B::A::a = 80;				// 以下四行报错// cout << d0.B::A::a << endl;	// d0.C::A::a = 70;// cout << d0.C::A::a << endl;  // 会发生二义性,因为有两条路径都可以访问到 Areturn 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

虚继承(virtual)

虚继承,指对公共基类的虚继承。
主要用于解决菱形继承问题,采用虚继承后,公共基类中的内容,只会在汇集子类中存在一份,在汇集子类中,可以通过任意一条路径访问到公共基类中的成员。在中间子类继承时加 virtual。
虚继承解决二义性主要通过虚基类指针和虚基类表实现,下例中的 类B、类C 会分别创建一个虚基类指针和虚基类表。所有同类型对象共用一张虚基类表,每个对象内部增加一个隐藏的虚基类指针成员变量,这个虚基类指针指向虚基类表。派生类D 中,也有隐藏的虚基类指针,但是没有自己虚基类表。在调用 A的成员时, D对象 会通过虚基类指针找到对应的虚基类表,通过查表避免二义性。

——> Solution
#include <iostream>
using namespace std;class A
{
public:int a;
};class B:virtual public A
{
};class C:virtual public A
{
};class D:public B, public C
{
};int main()
{D d0;d0.B::A::a = 90;cout << d0.C::A::a << endl;			// 成功打印 90,上一个问题得以解决return 0;
}
为每一个类添加构造函数
#include <iostream>
using namespace std;class A
{
public:int a;A(int a):a(a) {cout << "A" << endl; }
};class B:virtual public A
{
public:int b;B(int a, int b):A(a), b(b) {cout << "B" << endl; }
};class C:virtual public A
{
public:C(int a):A(a) {cout << "C" << endl; }	// B 和 C 哪一个先构造,取决于 D 在继承时的顺序
};class D:public C, public B			// 决定结果的顺序 为 C、B
{
public:D(int a, int b):B(a, b), C(a), A(a) {cout << "D" << endl; }		// B、C 可交换顺序,结果不变
};int main()
{D d0(12, 5);cout << d0.a << '\t' << d0.b << endl;d0.B::A::a = 90;cout << d0.C::A::a << endl;return 0;
}

在这里插入图片描述

#include <iostream>
using namespace std;class A
{
public:int a;A(int a):a(a) {cout << "A" << endl; }
};class B:virtual public A
{
public:int b;B(int a, int b):A(a), b(b) {cout << "B" << endl; }
};class C:virtual public A
{
public:C(int a):A(a) {cout << "C" << endl; }	// B 和 C 哪一个先构造,取决于 D 在继承时的顺序
};class D:public B, public C
{
public:D(int a, int b):C(a), B(a, b), A(a) {cout << "D" << endl; }		// B、C 可交换顺序
};int main()
{D d0(12, 5);cout << d0.a << '\t' << d0.b << endl;d0.B::A::a = 90;cout << d0.C::A::a << endl;return 0;
}

在这里插入图片描述

B 和 C 哪一个先构造,取决于 D 在继承时的顺序。

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

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

相关文章

接口测试之测试原则、测试用例、测试流程......

一、接口的介绍 软件测试中&#xff0c;常说的接口有两种&#xff1a;图形用户接口&#xff08;GUI&#xff0c;人与程序的接口&#xff09;、应用程序编程接口&#xff08;API&#xff09;。 接口&#xff08;API&#xff09;是系统与系统之间&#xff0c;模块与模块之间或者…

异常数据检测 | Python实现oneclassSVM模型异常数据检测

支持向量机(SVM)的异常检测 SVM通常应用于监督式学习,但OneClassSVM[8]算法可用于将异常检测这样的无监督式学习,它学习一个用于异常检测的决策函数其主要功能将新数据分类为与训练集相似的正常值或不相似的异常值。 OneClassSVM OneClassSVM的思想来源于这篇论文[9],SVM使用…

unity UGUI中获取点击位置处的URL链接

需求是&#xff0c;我们在一个text组件中像写网页那样写入链接&#xff0c;然后点击这个链接&#xff0c;就能访问配置的网页啥的。比如&#xff1a; <a href"hello">链接文本</a></summary> 最终的效果如下&#xff1a; 图中&#xff0c;image区…

华为智能手表独立导航,一呼即应轻松畅行

PetalMaps 手表独立导航&#xff0c;一声令下唤醒导航&#xff0c;打造了智慧的语音交互唤醒体验功能。导航时&#xff0c;语音播报、变道震动提醒功能&#xff0c;让您尽情体验腕上导航乐趣&#xff0c;同时又能安全抵达目的地。

通过滴滴技术博客:探寻造成此次P0故障的真正原因

2023年11月27日晚至2023年11月28日早晨&#xff0c;滴滴发生了长达12小时的P0级故障&#xff0c;导致滴滴核心业务都受到了影响&#xff0c;比如不显示定位无法打车、滴滴单车无法扫码等问题&#xff0c;期间滴滴进行了多次致歉 目前问题故障已经恢复&#xff0c;根据最新的消息…

Python使用pywebview开发桌面应用:打造现代化、跨平台的用户体验

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在当今科技快速发展的时代&#xff0c;为了提供更好的用户体验&#xff0c;许多应用程序都转向了桌面应用的开发。在Python领域&#xff0c;pywebview是一款优秀的库&#xff0c;它使得用Web技术开发桌面应用变得…

flask中路由route根据字典ID展示部分内容,字典名展示全部内容

from flask import Flask, jsonify , request,render_template,app Flask(__name__)app.config[JSON_AS_ASCII] Falsebooks [{"id": 1, "name": 三国演义},{"id": 2, "name": 水浒传},{"id": 3, "name": 西游记…

王道p18 2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为 O(1)。(c语言代码实现)

视频讲解在这&#xff08;谢谢各位大佬&#xff09;&#xff1a;&#x1f447; c语言代码实现数据结构课后代码题顺序表p18 2_哔哩哔哩_bilibili 本题代码如下 void nizhi(struct sqlist* s) {int temp 0;for (int i 0; i < s->length / 2; i){temp s->a[i];s-&…

【Springboot系列】SpringBoot整合Jpa

文章目录 前言&#xff1a;什么是JPA&#xff1f;JPA优缺点优点1.简化开发&#xff1a;2.高度抽象&#xff1a;3.跨数据库支持&#xff1a;4.自动化的事务管理&#xff1a; 缺点1.学习成本较高&#xff1a;2.性能问题&#xff1a;3.灵活性受限&#xff1a; 示例版本依赖代码Use…

linux 服务 下 redis 安装和 启动

官网下载 https://redis.io/download/ 安装步骤&#xff1a; 1.安装redis 所需要的依赖 yum install -y gcc tcl2.上传安装包并解压&#xff0c;下载安装包&#xff0c;上传到/usr/local/src目录&#xff0c;解压 tar -zxvf redis-7.2.3.tat.gz进入安装目录&#xff0c;运行…

【SK-learn学习】1.16 概率校准

一、说明 概率校准&#xff0c;指的是对于分类器而言&#xff0c;对应多种类别&#xff0c;概率最大就将样本归入&#xff0c;这个事实没有考虑置信度的问题。sklearn的calibration就是指的这种情形&#xff0c;参考本文。 二、关于sklearn.calibration的概念 执行分类时&#…

Haskell和http-client库下载代码示例

haskell import Network.HTTP.Client 然后&#xff0c;我们需要定义一个函数来下载视频。这个函数将接收一个URL作为参数&#xff0c;并返回一个IO动作&#xff0c;该动作将下载视频文件到当前目录。 haskell downloadVideo :: String -> IO () downloadVideo url do --…

Kubernetes(K8s)资源管理-03

资源管理 资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统&#xff0c;用户可以在集群中部署各种服务&#xff0c;所谓的部署服务&#xff0c;其实就是在kubernetes集…

【同一局域网下】访问其他电脑的虚拟机

一、在被连接的电脑上对VMware进行设置 编辑 --> 虚拟网络编辑器 按顺序点击 如果22端口已被占用&#xff0c;可以自行定义 &#xff08;端口号越大&#xff0c;被占用的可能性越小&#xff09; 二、在被连接的电脑上对防火墙进行设置&#xff08;这里以win11为例&#xff…

AppDelete 4.3.3(软件清理卸载工具)

AppDelete for Mac是一款运行在Mac平台上的强大软件卸载工具&#xff0c;AppDelete Mac版不仅可以删除应用程序&#xff0c;还可以删除小部件&#xff0c;首选项窗格&#xff0c;插件和屏幕保护程序及其相关文件&#xff0c;卸载快速又干净&#xff0c;仅需要简单的拖拽即可。 …

【端到端可微1】端到端的训练,使用反向传播,要求过程可微分

文章目录 背景想法&#xff1a; Weighted least-squares fitting方法&#xff1a; Backpropagating through the fitting procedure.温习之前的基础前向传播反向传播 总结 背景 想做一个端到端训练的模型&#xff0c;将最小二乘嵌入其中。因此有了这系列文章。 想法&#xff…

用本子堆经验,手把手教你怎么写国自然项目基金!

随着社会经济发展和科技进步&#xff0c;基金项目对创新性的要求越来越高。申请人需要提出独特且有前瞻性的研究问题&#xff0c;具备突破性的科学思路和方法。因此&#xff0c;基金项目申请往往需要进行跨学科的技术融合。申请人需要与不同领域结合&#xff0c;形成多学科交叉…

手机笔记工具怎么加密?

选择用手机笔记工具记事&#xff0c;大家可以记录很多学习笔记、读书笔记、私密日记等&#xff0c;手机作为随身携带的设备&#xff0c;记录相关的笔记比较快捷且方便&#xff0c;当手机笔记中记录的内容比较私密时&#xff0c;大家担心手机笔记会被别人误看&#xff0c;这时候…

无电机光电测径仪稳定性好

目前市面上的在线测径仪主要是有电机的激光扫描式测径仪与无电机的光电平行光测径仪。均能完成外径尺寸的高精度尺寸检测&#xff0c;本文来简单介绍一下无电机光电测径仪的优势。 光电测径仪检测原理 发射镜头内置一个点光源&#xff0c;点光源发出的光通过透镜系统&#xf…

Amazon CodeWhisperer 使用体验

文章作者&#xff1a;STRIVE Amazon CodeWhisperer 是最新的代码生成工具&#xff0c;支持多种编程语言&#xff0c;如 java,js,Python 等&#xff0c;能减少开发人员手敲代码时间&#xff0c;提升工作效率。PS:本人是一名 CodeWhisperer 业余爱好者 亚马逊云科技开发者社区为开…