c++中的继承和多态

news2024/9/27 17:36:40

目录

 

Linux中的管道通信

​编辑派生类的默认成员函数

继承 

 派生类的构造

 隐藏

如何设计一个不能被继承的类

菱形继承

virtual

virtual是如何解决的

内存对象模型

继承和组合

继承

组合

多态

概念

多态的构成条件

虚函数的重写

Linux中的管道通信

派生类的默认成员函数

1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函 数,则必须在派生类构造函数的初始化列表阶段显示调用。

2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。

3. 派生类的operator=必须要调用基类的operator=完成基类的复制。

4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类 对象先清理派生类成员再清理基类成员的顺序。

5. 派生类对象初始化先调用基类构造再调派生类构造。

6. 派生类对象析构清理先调用派生类析构再调基类的析构。

继承 

class Person
{
public:
	Person(const char* name = "peter")
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};

 派生类的构造

class Student : public Person
{
	Student(const char* name, int stuid)
		:Person(name)
		,_stuid(stuid)
	{}
private:
	int _stuid;
};

 Person(name)  相当于构造了一个匿名对象。

派生类的构造  其中有一部分继承自父类   只能自动调默认的构造函数(编译器默认生成的,全缺省的,无参的)

class Student : public Person
{
public:
	Student(const char* name, int stuid)
		:Person(name)
		,_stuid(stuid)
	{
		cout << "Student()" << endl;
	}
	Student(const Student& s)
		:Person(s)
		, _stuid(s._stuid)
	{
		cout << "Student(const Student& s)" << endl;
	}
private:
	int _stuid;
};

 隐藏

子类和父类有同名函数会构成隐藏

Person& operator=(const Person& p)
{
	cout << "Person operator=(const Person& p)" << endl;
	if (this != &p)
		_name = p._name;

	return *this;
}
Student& operator=(const Student& s)
{
	if (this != &s)
	{
		operator=(s);
		_stuid = s._stuid;
		cout << "Student& operator=(const Student& s)" << endl;
	}
	return *this;
}

子类隐藏了父类的operator=会引发堆栈溢出。

更正:

if (this != &s)
{
	Person::operator=(s);
	_stuid = s._stuid;
	cout << "Student& operator=(const Student& s)" << endl;
}

子类和父类的析构函数同样构成隐藏。因为其名字会被编译器替换为destructor.

~Student()
{
	//Person::~Person();
	cout << "~Student()" << endl;
}

结束时会自动调用父类的析构函数,因为这样才能保证先析构子类在析构父类

如何设计一个不能被继承的类

class A
{
private:
	A()
	{}
};
class B : public A
{};

构造函数私有化后,B类无法实例化出对象。

子类在调用构造函数时必须先调用父类的。

友元关系不能被继承。

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一 个static成员实例 。

菱形继承

class Person
{
public :
 string _name ; // 姓名
};
class Student : public Person
{
protected :
 int _num ; //学号
};
class Teacher : public Person
{
protected :
 int _id ; // 职工编号
};
class Assistant : public Student, public Teacher
{
protected :
 string _majorCourse ; // 主修课程
};
void Test ()
{
 // 这样会有二义性无法明确知道访问的是哪一个
 Assistant a ;
 a._name = "peter";
 
 // 需要显示指定访问哪个父类的成员可以解决二义性问题,但是数据冗余问题无法解决
 a.Student::_name = "xxx";
 a.Teacher::_name = "yyy";
}

virtual

虚拟继承可以解决菱形继承的二义性和数据冗余的问题。如上面的继承关系,在Student和Teacher的继承 Person时使用虚拟继承,即可解决问题。需要注意的是,虚拟继承不要在其他地方去使用。

class Student : virtual public Person
{
protected :
 int _num ; //学号
};
class Teacher : virtual public Person
{
protected :
 int _id ; // 职工编号
};

virtual是如何解决的

c++的缺陷有那些?

多继承->菱形继承->虚继承->底层结构的对象模型非常复杂,且有一定的效率损失。

什么事菱形继承?菱形继承存在的问题?如何解决?-> 虚继承  虚继承的解决原理是什么?

内存对象模型

对象在内存中是如何存的?

class A
{
public:
	int _a;
};

// class B : public A
class B : virtual public A
{
public:
	int _b;
};

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

int main()
{
	D d;
	cout << sizeof(d) << endl;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	d._a = 6;
	return 0;
}

继承和组合

都可以完成类层次的复用

public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。

组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。

继承

继承是一种白箱复用,父类对子类基本是透明的,但在一定程度上破坏了父类的封装性。

class A{};
class B : class A
{};

例如:车和车品牌之间的关系 

组合

组合是一种黑箱复用,c对d是不透明的,很好的保持了c的封装性。

class C {};
class D
{
    C c;
};

例如轮胎和车的关系。

多态

概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。

多态的构成条件

1. 必须通过基类的指针或者引用调用虚函数

2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类 型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

class Person {
public:
 virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
 
class Student : public Person {
public:
 virtual void BuyTicket() { cout << "买票-半价" << endl; }
/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后
基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/
 /*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
 
void Func(Person& p)
{ p.BuyTicket(); }
 
int main()
{
 Person ps;
 Student st;
 
 Func(ps);
 Func(st);
 
 return 0;
}

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

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

相关文章

[数据集][目标检测]俯拍航拍森林火灾检测数据集VOC+YOLO格式6116张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6116 标注数量(xml文件个数)&#xff1a;6116 标注数量(txt文件个数)&#xff1a;6116 标注…

Lombok介绍

一、Lombok 1.1何为Lombok Lombok是Java的一个库&#xff0c;是一个工具&#xff0c;使用这个工具能够使得我们通过使用注解的方式减少Java中代码的开发。其简化主要是针对Java中的简单Java对象(就是无继承、无实现的)类。我们化简的就是这些类中重复冗余出现的构造函数&#…

运算符学习

ctrlaltL 自动格式化代码 原码反码补码 负数用反码去计算不会出错。跨零就会出错。补码解决了 字节-128到127

双指针的用法以及示例

当然可以&#xff01;双指针&#xff08;Two Pointers&#xff09;是一种常用的算法技巧&#xff0c;特别适用于处理数组或链表等线性数据结构的问题。以下是双指针用法的总结&#xff1a; 双指针用法总结 基本概念&#xff1a; 双指针技术使用两个指针在数据结构上进行遍历&a…

SpringBoot集成Thymeleaf模板引擎,为什么使用(详细介绍)

学习本技术第一件事&#xff1a;你为什么要使用&#xff0c;解决什么问题的&#xff1f; 1.为什么使用&#xff08;使用背景&#xff09;&#xff1f; 首先应用场景是单体项目&#xff0c;如果是前后端分离就不用关注这个了&#xff0c;因为单体项目你前后端都是写在一个项目…

关于决策树的一些介绍(二)

我之前写过一篇关于决策树的文章&#xff0c;但在那篇文章里没有提及基尼系数&#xff0c;信息熵与信息增益等相关问题&#xff0c;所以我将在这篇文章中进行补充。 一、 决策树的一份python代码 首先&#xff0c;我先给出一份最基础的决策树代码&#xff0c;在这里&#xff…

在 Python 画图中同时设置中英文字体

前言 在使用matplotlib.pyplot画图时&#xff0c;默认情况下都是黑体字&#xff0c;很不美观。如果含有中文&#xff0c;可能无法显示&#xff1b;显示了中文之后英文字体就不能使用。本文针对这些问题逐一给出解决方案。 同时设置中英文字体 我们都知道&#xff0c;按照下面的…

00898 互联网软件应用与开发自考复习

资料来自互联网软件应用与开发大纲 南京航空航天大学 高纲4295和JSP 应用与开发技术(第 3 版) 马建红、李学相 清华大学出版社2019年 识记:要求考生能够识别和记忆本课程中有关互联网软件开发与应用的概念性内容,并能够根据考核的不同要求,做出正确的表述、选择和判断。领会…

合资油车断崖式崩盘,买车的千万慎重了

文 | AUTO芯球 作者 | 雷慢 合资车&#xff0c;燃油车全体大逃亡的时候来了&#xff0c; 你敢信吗&#xff0c;8月份&#xff0c;国内新能源汽车零售渗透率达到54%&#xff0c; 我给大家讲个冷笑话&#xff0c; 几个月前还有车企老总说什么&#xff0c; “只要传统车企一发…

linux 操作系统下的curl 命令介绍和使用案例

linux 操作系统下的curl 命令介绍和使用案例 1. curl 命令简介 curl 是一个利用 URL 规则在命令行下工作的文件传输工具。它支持文件的上传和下载&#xff0c;是综合传输工具&#xff0c;但传输的协议主要是 HTTP/HTTPS 和 FTP。curl 还支持很多种类型的服务器认证方式&#…

网络(三)——协议是什么???

文章目录 协议的概念结构化数据网络计算机服务端定制协议客户端代码 协议的概念 计算机之间的传输媒介是光信号和电信号。通过 “频率” 和 “强弱” 来表示 0 和 1 这样的信息。要想传递各种不同的信息&#xff0c;就需要约定好双方的数据格式。 结构化数据 我们知道TCP是面向…

Linux基础---07文件传输(网络和Win文件)

Linux文件传输地图如下&#xff0c;先选取你所需的场景&#xff0c;若你是需要Linux和Linux之间传输文件就查看SCP工具即可。 一.下载网站文件 前提是有网&#xff1a; 检查网络是否畅通命令&#xff1a;ping www.baidu.com&#xff0c;若有持续的返回值就说明网络畅通。Ctr…

请查收《网安问答秘籍》

在数字化日益普及的今天&#xff0c;网络安全威胁层出不穷&#xff0c;保护个人隐私和数据安全成为每个人的必修课。秘籍精选了最实用的网络安全问答&#xff0c;广大群众及时了解网络安全知识&#xff0c;提升网络安全意识&#xff0c;有效防范网络诈骗&#xff0c;确保个人信…

获取无人机经纬度是否在指定禁飞区内

1. 计算公式: (AB X AE ) * (CD X CE) >= 0 && (DA X DE ) * (BC X BE) >= 0 参考: 判断点是否在矩形框(多边形)内_qt opencv 判断一点是否在矩形内-CSDN博客 2.测试结果: 3.实现完整代码: #include<cstd

【系统规划与管理师】【案例分析】【考点】【答案篇】第7章 IT服务持续改进

【问题篇】☞【系统规划与管理师】【案例分析】【考点】【问题篇】第7章 IT服务持续改进 【移动端浏览】☞【系统规划与管理师】【案例分析】【模拟考题】章节考题汇总&#xff08;第7章&#xff09;&#xff08;答案篇&#xff09;&#xff08;共11个知识点&#xff09; 第7章…

在服务器上开Juypter Lab教程(远程访问)

在服务器上开Juypter Lab教程&#xff08;远程访问&#xff09; 文章目录 在服务器上开Juypter Lab教程&#xff08;远程访问&#xff09;一、安装anaconda1、安装anaconda2、提权限3、运行4、同意协议5、安装6、是否要自动初始化 conda7、结束8、检查 二、Anaconda安装Pytorch…

使用Docker挂载部署JAVA项目

用于需要使用Docker容器部署项目&#xff0c;但可能部署包需多次调整的场景&#xff0c;这种部署方式可以减少镜像制作的过程&#xff1b; 推荐几个使用Docker安装环境的文章&#xff1a; 1.Nocas: https://blog.csdn.net/weixin_44700323/article/details/140995859 2.Mysql: …

学习大数据DAY57 新的接口配置

作业  完成 API 接口和文件的接入, 并部署到生产调度平台, 每个任务最后至少 要有两条 不报错 的日志, 报错就驳回作业  作业不需要复制日志 API Appliation Program Interface 应用程序接口 > JSON 的地址 客户需求: 把 https://zhiyun.pub:9099/site/c-class…

从“看”到“管”:EasyCVR安防监控平台如何推动城市管理模式的转型升级

在21世纪的今天&#xff0c;随着城市化进程的加速推进&#xff0c;城市规模不断扩大&#xff0c;人口密集度显著增加&#xff0c;城市管理面临着前所未有的挑战。从公共安全、交通管理到环境保护、应急响应&#xff0c;每一个领域都对城市的治理能力和效率提出了更高要求。在这…

PowerShell install 一键部署Oracle23ai

Oracle23ai前言 Oracle Database 23ai Free 让您可以充分体验 Oracle Database 的能力,世界各地的企业都依赖它来处理关键任务工作负载。 Oracle Database Free 的资源限制为 2 个 CPU(前台进程)、2 GB 的 RAM 和 12 GB 的磁盘用户数据。该软件包不仅易于使用,还可轻松下载…