浅谈C++|类的继承篇

news2024/12/25 12:46:21

 

引子: 

继承是面向对象三大特性之一、有些类与类之间存在特殊的关系,例如下图中:



我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。
这个时候我们就可以考虑利用继承的技术,减少重复代码。

一.继承基本语法 

语法:class 子类:继承方式 父类 

优点:减少重复代码

子类也叫派生类,父类也叫基类

代码: 

#include <iostream>
using namespace std;
class person {   //定义person基类
public:
	int age;
	int height;
	int weight;
	string name;

	void show() {
		cout << "age=" << age << endl;
		cout << "height=" << height << endl;
		cout << "weight=" << weight << endl;
		cout << "name=" << name << endl;
	}
};

class women :public person {
public:
	string xingbie;
	void shou_x() {
		cout << "xingbie=" << xingbie<<endl;
	}
};

void fun() {
	women p;
	p.age = 18;
	p.height = 180;
	p.name = "tom";
	p.weight = 160;
	p.xingbie = "女";
	p.show();
	p.shou_x();
}
int main() {
	fun();
	return 0;
}

 派生类中的成员,包含两大部分:
1.类是从基类继承过来的,-类是自己增加的成员。
2.从基类继承过过来的表现其共性,而新增的成员体现了其个性。

 二.继承方式

 继承方式:

public:     公有继承

protected:保护继承

private:    私有继承

代码:

#include <iostream>
using namespace std;
class father {
public:
	int A;
protected:
	int B;
private:
	int C;
};

class son1 :public father {    //公有继承
public:
	void fun() {
		cout << "A=" << A << endl;  //公有变为公有
		cout << "B=" << B << endl;  //保护变为保护
		//cout << "C=" << C << endl;//私有不可访问
	}
};

class son2 :protected father {    //保护继承
public:
	void fun() {
		cout << "A=" << A << endl;  //公有变为保护
		cout << "B=" << B << endl;  //保护变为保护
		//cout << "C=" << C << endl;//私有不可访问
	}
};


class son3 :private father {    //私有继承
public:
	void fun() {
		cout << "A=" << A << endl;  //公有变为私有
		cout << "B=" << B << endl;  //保护变为私有
		//cout << "C=" << C << endl;//私有不可访问
	}
};


void fun() {
	son1 p1;
	son2 p2;
	son3 p3;
	p1.A = 10;
	p1.fun();
}
int main() {
	fun();
	return 0;
}

 私有成员全不见,公不变,保全保,私全私。

 三.继承中的对象模型

继承中,基类私有变量虽然访问不到,但是已经被继承,只是被隐藏了。

 代码:

#include <iostream>
using namespace std;
class father {
public:
	int A;
protected:
	int B;
private:
	int C;
};
class son :private father {
public:
	int age;
};
int main() {
	cout << sizeof(son) << endl;
	return 0;
}

四.继承构造和析构顺序

子类继承父类时,会先创建一个父类。析构的顺序和构造顺序正好相反。

 代码:

#include <iostream>
using namespace std;
class father {
public:
	father() {
		cout << "father的构造哈数" << endl;
	}
	~father() {
		cout << "father的析构函数" << endl;
	}
};
class son :public father {
public:
	son() {
		cout << "son的构造函数" << endl;
	}
	~son() {
		cout << "son的析构函数" << endl;
	}
};
void fun() {
	son a;
}
int main() {
	fun();
	return 0;
}

五.继承同名成员处理方式

当基类中的成员变量以及成员函数,和派生类的成员变量和函数重名时,基类默认调用派生类的成员函数和成员变量。要想调用基类的成员函数和成员变量,需要加上基类的作用域;

代码:

#include <iostream>
using namespace std;
class father {
public:
	int A;
	father() {
		A = 999;
	}
	void fun() {
		cout << "father的fun调用" << endl;
	}
	void fun(int a) {
		cout << "father的fun调用" << ' ' << a << endl;
	}
};
class son :public father{
public:
	int A;
	son() {
		A = 99;
	}
	void fun() {
		cout << "son的fun调用" << endl;
	}
	void fun(int a) {
		cout << "father的fun调用" << ' ' << a << endl;
	}
};
void fun() {
	son p;
	cout << "son" << ' ' << p.A << endl;
	cout << "father" << ' ' << p.father::A << endl;
	p.fun();
	p.fun(11);
	p.father::fun();
	p.father::fun(90);
}
int main() {
	fun();
	return 0;
}

 如果派生类中出现和基类重名的成员函数,那么派生类会隐藏基类全部重名的成员函数。需要注意的是,本来可以按照函数重载区分,却被派生类隐藏的情况:

代码: 

#include <iostream>
using namespace std;
class father {
public:
	int A;
	father() {
		A = 999;
	}
	
	void fun() {
		cout << "father的fun调用" << endl;
	}
	void fun(int a,int b) {
		cout << "father的fun调用" << ' ' << a << endl;
	}
};
class son :public father{
public:
	int A;
	son() {
		A = 99;
	}
	void fun() {
		cout << "son的fun调用" << endl;
	}
};
void fun() {
	son p;
	cout << "son" << ' ' << p.A << endl;
	cout << "father" << ' ' << p.father::A << endl;
	p.fun();
	p.fun();
	p.father::fun();
	//p.fun(90,89);//报错
	p.father::fun(89, 123);
}
int main() {
	fun();
	return 0;
}

六.继承同名static成员处理方式

 当重名的成员变量和函数是static时,需要注意通过类名来调用的方式

代码:

#include <iostream>
using namespace std;
class father {
public:
	static int A;
	static void fun() {
		cout << "father的fun调用" << endl;
	}
	void fun(int a) {
		cout << "father的fun调用" << a<<' ' << endl;
	}
};
int father::A=10;   //static成员变量,类内声明,类外定义
class son :public father {
public:
	static int A;
	static void fun() {
		cout << "son的fun调用" << endl;
	}
};
int son::A = 20;
void fun() {
	son p;
	//1.利用对象调用成员变量和函数
	cout << p.A << endl;
	cout << p.father::A << endl;
	p.fun();
	p.father::fun();

	cout << "**************************" << endl;
	//2.利用类名调用成员变量和函数
	cout << son::A << endl;
	cout << father::A << endl;
	cout << son::father::A << endl;   

	son::fun();
	father::fun();
	son::father::fun();    
	//father::fun(10);  //报错,此方法只能调用static类型


}
int main() {
	fun();
	return 0;
}

七.多继承语法

C++中允许一个类继承多个类


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


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

 代码:

#include <iostream>
using namespace std;
class base1 {
public:
	int A;
	base1() {
		A = 10;
		cout << "base1构造函数调用" << endl;
	}
};


class base2 {
public:
	int A;
	base2() {
		A = 20;
		cout << "base2构造函数调用" << endl;
	}
};

class son :public base1, public base2 {
public:
	int B;
	int C;
	son() {
		B = 100;
		C = 200;
		cout << "son构造函数调用" << endl;
	}
};

void fun() {
	son b;
	cout << b.base1::A << endl;
	cout << b.base2::A << endl;
	cout << b.B << endl;
	cout << b.C << endl;
}
int main() {
	fun();
	return 0;
}

 

 注意构造函数的调用顺序,父亲1先调用,父亲2再调用,最后son调用

总结:多继承中如果父类中出现了同名情况,子类使用时候要加作用域。

八.菱形继承

菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承者两个派生类
这种继承被称为菱形继承,或者钻石继承

1.羊继承了动物的数据,驼同样继承了动物的数据,当羊驼使用数据时,就会产生二义性。
2.羊驼将动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要—份就可以。

 代码:

#include <iostream>
using namespace std;
class dongwu {
public:
	int A;
};
class yang :public dongwu {};
class tuo:public dongwu {};
class son :public tuo, public yang {};
void fun() {
	son p;
	p.yang::A = 100;
	p.tuo::A = 200;
	//当菱形继承,两个父亲拥有相同名的成员时,要加作用域加以区分;
	cout << p.yang::A << endl;
	cout << p.tuo::A << endl;
}
int main() {
	fun();
	return 0;
}

此时的继承情况是,这样的。 

 利用虚继承,可以解决菱形继承的问题(两份相同的数据,浪费内存)

代码:

#include <iostream>
using namespace std;
class dongwu {
public:
	int A;
};
//virtual虚继承,dongwu称为虚基类
class yang :virtual public dongwu {};
class tuo:virtual public dongwu {};
class son :public tuo, public yang {};
void fun() {
	son p;
	yang p1;
	tuo p2;
	p.yang::A = 100;
	p.tuo::A = 200;
	p1.A = 90;
	p2.A = 190;
	//当菱形继承,两个父亲拥有相同名的成员时,要加作用域加以区分;
	cout << p.yang::A << endl;
	cout << p.tuo::A << endl;
	cout << p1.A << endl;
	cout << p2.A << endl;

}
int main() {
	fun();
	return 0;
}

 继承时只继承一份,此时son继承的是两个虚基类表的指针,虚基类表中存储的是到成员的偏移量。

总结:
·菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义·利用虚继承可以解决菱形继承问题

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

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

相关文章

Learn Prompt-人工智能基础

什么是人工智能&#xff1f;很多人能举出很多例子说这就是人工智能&#xff0c;但是让我们给它定义一个概念大家又觉得很难描述的清楚。实际上&#xff0c;人工智能并不是计算机科学领域专属的概念&#xff0c;在其他学科包括神经科学、心理学、哲学等也有人工智能的概念以及相…

机器学习第六课--朴素贝叶斯

朴素贝叶斯广泛地应用在文本分类任务中&#xff0c;其中最为经典的场景为垃圾文本分类(如垃圾邮件分类:给定一个邮件&#xff0c;把它自动分类为垃圾或者正常邮件)。这个任务本身是属于文本分析任务&#xff0c;因为对应的数据均为文本类型&#xff0c;所以对于此类任务我们首先…

Jprofiler的使用查看oom

一、安装 idea安装插件 安装客户端 链接 IDEA配置Jprofiler执行文件 二、产生oom import java.util.ArrayList; import java.util.List;//测试代码 public class TestHeap {public static void main(String[] args) {int num 0;List<Heap> list new ArrayList&l…

【深度学习实验】线性模型(一):使用NumPy实现简单线性模型:搭建、构造损失函数、计算损失值

目录 一、实验介绍 二、实验环境 三、实验内容 0. 导入库 1. linear_model函数 2. loss_function函数 3. 定义数据 4. 调用函数 一、实验介绍 使用Numpy实现 线性模型搭建构造损失函数进行模型前向传播并计算损失值 二、实验环境 conda create -n DL python3.7 cond…

Learn Prompt-什么是ChatGPT?

ChatGPT&#xff08;生成式预训练变换器&#xff09;是由 OpenAI 在2022年11月推出的聊天机器人。它建立在 OpenAI 的 GPT-3.5 大型语言模型之上&#xff0c;并采用了监督学习和强化学习技术进行了微调。 ChatGPT 是一种聊天机器人&#xff0c;允许用户与基于计算机的代理进行对…

LVS+Haproxy

LVSHaproxy 一、Haproxy简介1.1、Haproxy应用分析1.2、Haproxy的特性1.3、常见负载均衡策略1.4、LVS、Haproxy、Nginx区别1.5、 Haproxy的优点1.6、常见的Web集群调度器 二、Haproxy部署实例四、日志定义优化 一、Haproxy简介 Haproxy 是一个使用C语言编写的自由及开放源代码软…

ES6中新增加的Proxy对象及其使用方式

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ Proxy对象的基本概念Proxy对象的主要陷阱&#xff08;Traps&#xff09; ⭐ 使用Proxy对象⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来…

Hugging Face使用Stable diffusion Diffusers Transformers Accelerate Pipelines

Diffusers A library that offers an implementation of various diffusion models, including text-to-image models. 提供不同扩散模型的实现的库&#xff0c;代码上最简洁&#xff0c;国内的问题是 huggingface 需要翻墙。 Transformers A Hugging Face library that pr…

log4j2漏洞复现

log4j2漏洞复现 漏洞原理 log4j2框架下的lookup查询服务提供了{}字段解析功能&#xff0c;传进去的值会被直接解析。例如${sys:java.version}会被替换为对应的java版本。这样如果不对lookup的出栈进行限制&#xff0c;就有可能让查询指向任何服务&#xff08;可能是攻击者部署…

JavaScript-箭头函数

es6的箭头函数具体使用 es6之后提出了箭头函数 更加简洁方便 注意 &#xff1a; 特点:只有一个形参可以省略括号 大括号是否可以省略&#xff1f; 是 只有一句代码的时候可以省略 具体看代码演示&#xff1a; 代码 <!DOCTYPE html> <html lang"en"&…

Python 图形化界面基础篇:处理鼠标事件

Python 图形化界面基础篇&#xff1a;处理鼠标事件 引言 Tkinter 库简介步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口步骤3&#xff1a;创建一个 Canvas 画布步骤4&#xff1a;处理鼠标事件步骤5&#xff1a;启动 Tkinter 主事件循环 完整示例代码代…

解决中国科大 USTC 邮箱系统的超大附件上传的邮箱控件安装问题

USTC邮箱系统上传超过 48M 的附件的步骤&#xff1a; 从文件中转站上传文件&#xff0c;会提示下载邮箱控件 cmplugin_setup.exe &#xff0c;默认安装C盘即可 2. 安装好之后依然无法上传超大文件&#xff0c;因为只有 IE 浏览器支持该功能&#xff0c;所以可以使用 Edge 浏览…

timer trigger function

创建&#xff08;使用vscode&#xff09; 选择Timer trigger 命名 设置多久触发一次&#xff08;该语句是5分钟一次&#xff09; 创建完成 在下面直接编辑想要运行的代码。

【计算机网络】75 张图详解:网络设备、网络地址规划、静态路由(万字长文)

75 张图详解&#xff1a;网络设备、网络地址规划、静态路由 1.网络设备1.1 交换机1.2 路由器 2.网络地址规划2.1 IP 地址2.2 分类地址2.3 子网掩码2.4 无类地址2.5 子网划分2.5.1 示例一2.5.2 示例二 2.6 超网合并 3.静态路由3.1 路由表3.2 直连路由3.3 静态路由3.4 默认路由3.…

OpenCV之怀旧色、冰冻滤镜、熔铸滤镜

怀旧色 源码&#xff1a; void huaijiu(Mat& src,Mat& dst) {for (int h 0;h < src.rows;h ){uchar *d1 src.ptr<uchar>(h);uchar *d2 dst.ptr<uchar>(h);for (int w 0;w < src.cols;w ){int w3 3*w;int r d1[w3 2];int g d1[w3 1];int …

这种长海报制作技巧大揭秘,让你的作品与众不同

制作吸引人的长图海报&#xff0c;是许多人在社交媒体、广告宣传、活动策划等场合中经常需要面对的任务。然而&#xff0c;对于不熟悉设计软件的人来说&#xff0c;这可能是一个挑战。幸运的是&#xff0c;现在有许多在线工具和模板可以帮助我们解决这个问题。下面&#xff0c;…

索引-动图演示存储过程

索引 二叉树存储过程演示 BThree存储过程 sql二级索引搜索过程 Id是唯一键&#xff0c;聚集索引 只存在一个 Name是二级索引 可以存在多个 第一种效率更高&#xff0c;不需要回表

C语言经典100例题(56-60)--画圆;画方;画线

目录 【程序56】题目&#xff1a;画图&#xff0c;学用circle画圆形 【程序57】题目&#xff1a;画图&#xff0c;学用line画直线。 【程序58】题目&#xff1a;画图&#xff0c;学用rectangle画方形。 【程序59】题目&#xff1a;画图&#xff0c;综合例子。 【程序60】题…

idea移除许可证

目录 一、介绍 二、操作步骤 一、介绍 当自己的idea日期要到了&#xff0c;又想续上&#xff0c;但是覆盖不了之前的日期&#xff0c;新的没办法生效。那么就要把原先的许可证先移除&#xff0c;再重新续上新的。 二、操作步骤 1.点击idea的右上角的这个展开 2.选择帮助…

二叉搜索树经典笔试题【力扣、牛客】

文章目录 1.根据二叉树创建字符串2. 二叉树的层序遍历3.二叉树的层序遍历Ⅱ4.二叉树的最近公共祖先1.法一&#xff1a;定位p、q在左还是右 分类讨论2.法二&#xff1a;利用stack求出p、q路径 求相交值 5.二叉搜索树与双向链表1.法一&#xff1a;递归&#xff1a;递归过程修正指…