菱形继承的类对父类的初始化、组合、多态、多态的原理等的介绍

文章目录

  • 前言
  • 一、菱形继承的类对父类的初始化
  • 二、组合
  • 三、 多态
    • 1. 构成多态
    • 2. 虚函数
    • 3. 虚函数的重写
    • 4. 虚函数重写的两个例外
      • 1. 协变
      • 2. 析构函数的重写
    • 5. C++11 final 和 override
      • 1. final
      • 2. override
    • 6. 设计不想被继承的类
    • 7. 重载、覆盖(重写)、 隐藏(重定义)的对比
  • 四、多态的原理
  • 总结


前言

菱形继承的类对父类的初始化、组合、多态、多态的原理等的介绍


一、菱形继承的类对父类的初始化

#include<iostream>
#include <string>
using namespace std;

class A
{
public:
	A(const char* A)
		:_a(A)
	{
		cout << "class A" << endl;
	}
	string _a;
};

class B : virtual public A
{
public:
	B(const char* A, const  char* B)
		:A(A)
		,_b(B)
	{
		cout << "class B" << endl;
	}
	string _b;
};

class C : virtual public A
{
public:
	C(const char* A, const char* C)
		:A(A)
		,_c(C)
	{
		cout << "class C" << endl;
	}
	string _c;
};

class D : public B, public C
{
public:
	D(const char* A, const char* B, const char* C, const char* D)
		: A(A)
		, B(A, B)
		, C(A, C)
		, _d(D)
	{
		cout << "class D" << endl;
	}
	string _d;
};


int main()
{

	D d("class A", "class B", "class C", "class D");
	
	return 0;
}

结构为:
在这里插入图片描述

  • 因为D类有如上的结构,所以A类会在D类中调用构造函数初始化,并且只调用一次,在D类中初始化B类和C类时,传入的A类不调用A类的构造函数初始化。

在这里插入图片描述

二、组合

  • public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
  • 组合是一种has-a的关系。假设B组合了A,每个B对象中都有一个A对象。

优先使用对象组合,而不是类继承。

#include <iostream>
using namespace std;

class A
{
protected:
	int _a;
};

class B : public A
{
protected:
	A _bb;
};

int main()
{

	return 0;
}

三、 多态

1. 构成多态

构成多态需要两个条件:

  1. 必须通过基类的指针或者引用调用虚函数
  2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写
// 构成多态
#include<iostream>
using namespace std;

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---全价" << endl;
	}
};

class Student : public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---半价" << endl;
	}
};

//void fun(Person& p)
//{
//	p.BuyTicket();
//}

void fun(Person* p)
{
	p->BuyTicket();
}

int main()
{
	Person p;
	fun(&p);

	Student s;
	fun(&s);

	return 0;
}

在这里插入图片描述

2. 虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---全价" << endl;
	}
};

3. 虚函数的重写

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

在重写基类的虚函数的时候,虽然派生类的虚函数不写virtual也可以构成重写, 但是不建议这样使用

#include<iostream>
using namespace std;

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---全价" << endl;
	}
};

class Student : public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---半价" << endl;
	}
};

4. 虚函数重写的两个例外

1. 协变

基类与派生类虚函数返回值类型不同。

简单来讲就是 基类与派生类的虚函数的返回值构成父子类指针或引用关系。

#include <iostream>
using namespace std;

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

class Person
{
public:
	virtual A* BuyTicket()
	{
		cout << "购票---全价" << endl;
		return new A;
	}
};

class Student : public Person
{
public:
	virtual B* BuyTicket()
	{
		cout << "购票---半价" << endl;
		return new B;
	}
};

void fun(Person& p)
{
	p.BuyTicket();
}


int main()
{
	Person p;
	fun(p);
	Student s;
	fun(s);
	return 0;
}
  • 基类和派生类构成父子类指针的关系

在这里插入图片描述

2. 析构函数的重写

虽然基类和派生类的析构函数的函数名不同,但是编译器会将析构函数的函数名,都处理成destructor,因此可以构成重写。

一般情况下,应该将派生类的析构函数与基类析构函数构成函数重写,使下面的情况delete可以实现多态,保证指向的对象正确调用析构函数。

析构函数可以构成虚函数重写吗, 为什么要构成虚函数重写?

  1. 析构函数加virtual会构成析构函数,因为编译器会将析构函数的名字统一命名为destructor
  2. 构成虚函数重写是因为,我们new一个派生类对象的空间,但是用基类的类型指针接收
  3. 在析构这个对象时,只会进行普通调用,普通调用会按照当前类型, 则只会调用基类的析构函数
  4. 这种情况,我们希望是一个多态调用,按照指向的类型调用析构函数,就需要构成虚函数的重写。
#include <iostream>
using namespace std;


class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---全价" << endl;
	}

	 virtual ~Person()
	{
		cout << " ~Person() " << endl;
	}
};

class Student : public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---半价" << endl;
	}

	virtual ~Student()
	{
		cout << " ~Student() " << endl;
	}
};

int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;

	delete p1;
	delete p2; // p2->destuctor() + operator delete(p)

	// 这里我们期望是一个多态调用,而不是普通调用

	p1 = nullptr;
	p2 = nullptr;

	return 0;
}

在这里插入图片描述

5. C++11 final 和 override

1. final

final 修饰的虚函数不能被重写

在这里插入图片描述

final修饰的类,不能被当做基类, 不能被继承

在这里插入图片描述

2. override

检查派生类中的虚函数与基类中虚函数是否构成重写,若不构成重写则报错。

#include <iostream>
using namespace std;


class Person
{
public:
	virtual void BuyTicket()
	{}

};

class Student : public Person
{
public:
	// 检查派生类中的虚函数与基类中的虚函数是否构成重写
	virtual void BuyTicket()override
	{
		cout << "购票---半价" << endl;
	}
};


int main()
{
	Person p;

	return 0;
}

在这里插入图片描述

6. 设计不想被继承的类

将构造函数私有或者将析构函数私有

将构造函数私有

#include <iostream>
using namespace std;

class A
{
public:
	static A CreateObj()
	{
		return A();
	}
private:
	A() {}

};

int main()
{
	A::CreateObj();
	return 0;
}

在这里插入图片描述

7. 重载、覆盖(重写)、 隐藏(重定义)的对比

在这里插入图片描述

四、多态的原理

普通调用在编译时地址就确定了
多态调用在程序运行时,到指向对象的虚函数表中找函数的地址

#include <iostream>
using namespace std;

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---全价" << endl;
	}

	int _a = 0;

};

class Student: public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "购票---半价" << endl;
	}

	int _b = 1;
};

// 普通调用
//void fun(Person p)
//{
//	p.BuyTicket();
//}

// 多态调用
void fun(Person& p)
{
	p.BuyTicket();
}

int main()
{
	Person p;

	Student s;


	return 0;
}

在这里插入图片描述


总结

菱形继承的类对父类的初始化、组合、多态、多态的原理等的介绍

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

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

相关文章

MoFA: 迈向AIOS

再一次向朋友们致以中秋的祝福&#xff01; MoFA (Modular Framework for Agents)是一个独特的模块化AI智能体框架。MoFA以组合&#xff08;Composition)的逻辑和编程&#xff08;Programmable&#xff09;的方法构建AI智能体。开发者通过模版的继承、编程、定制智能体&#xf…

黑马智数Day4-2

渲染基础Table列表 封装获取企业列表接口 export function getEnterpriseListAPI(params) {return request({url: /park/enterprise,params}) } 组件中获取数据 <script> import { getEnterpriseListAPI } from /apis/enterprise export default {name: Building,dat…

QT C++ 自学积累 『非技术文』

QT C 自学积累 『非技术文』 最近一段时间参与了一个 QT 项目的开发&#xff0c;使用的是 C 语法&#xff0c;很遗憾的是我之前从来没有接触过 C &#xff0c;大学没有开过这堂课&#xff0c;也没用自己学习过&#xff0c;所有说上手贼慢&#xff0c;到现在为止其实也不是很清楚…

大数据毕业设计选题推荐-超市进货推荐系统-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

如何瞬间建造一个百亿商品的网上商城?借助API,无需逐个上传商品数据,自动对接电商平台百亿商品数据

在快速发展的电商时代&#xff0c;构建一个拥有百亿级商品数据的网上商城曾是许多企业遥不可及的梦想。然而&#xff0c;随着技术的不断进步&#xff0c;特别是电商平台API接口的广泛应用&#xff0c;这一梦想正逐渐变为现实。本文将详细介绍如何通过调用电商平台API接口&#…

# 高可用的并发解决方案nginx+keepalived(四)

高可用的并发解决方案nginxkeepalived&#xff08;四&#xff09; 一、Keepalived安装 1、keepalived 介绍 Keepalived 是一种高性能的服务器高可用或热备解决方案&#xff0c;Keepalived 可以用来防止服务器单点故障的发生&#xff0c;通过配合 Nginx 可以实现 web 前端服务…

Git从了解到操作

Git常用命令 基本的linux命令 ls / ll 查看当前目录( ls 是查看目录有哪些文件夹&#xff0c;ll 是查看隐藏文件)cat 查看文件内容touch 创建文件vi vi编辑器 (使用 vi 编辑器是为了方便展示效果&#xff0c;也可以记事本、editPlus、notPad等其它编辑器) 备注 Git GUl: Gi…

Coze:如何使用插件商店?

你好&#xff0c;我是三桥君 本节我们来介绍插件商店。 点击左侧菜单的插件商店。可以看到&#xff0c;打开了插件商店的页面。 插件商店的顶部是“搜索框”&#xff0c;这里可以搜索整个插件商店的插件。 比如&#xff0c;我们输入“图片”进行搜索&#xff0c;会发现下方列…

华为昇腾系列-jupyter安装torch_npu

使用背景 国产算力的兴起&#xff0c;异构算力成为各大厂商的选择&#xff0c;以摆脱对英伟达算力过大的依赖&#xff0c;保障算力安全。本文将会讲解如何使用昇腾算力卡来制作一个镜像&#xff0c;然后交给k8s进行算力调度&#xff0c;显示国产算力的真正应用落地。 安装步骤…

【Python篇】深入机器学习核心:XGBoost 从入门到实战

文章目录 XGBoost 完整学习指南&#xff1a;从零开始掌握梯度提升1. 前言2. 什么是XGBoost&#xff1f;2.1 梯度提升简介 3. 安装 XGBoost4. 数据准备4.1 加载数据4.2 数据集划分 5. XGBoost 基础操作5.1 转换为 DMatrix 格式5.2 设置参数5.3 模型训练5.4 预测 6. 模型评估7. 超…

网络安全前景大好,转行这些职位成了“香饽饽”

网络安全就业前景 大数据、人工智能、云计算、物联网、5G等新兴技术的高速发展&#xff0c;蒸蒸日上。但是随之也出现了许多问题&#xff0c;比如&#xff1a;政府单位、企业、个人信息泄露&#xff0c;网络安全问题日益严峻&#xff0c;网络空间安全建设刻不容缓。 网络安全…

真正厉害的项目经理都做到了这一点

在项目管理中&#xff0c;沟通是贯穿始终的关键要素&#xff0c;它能够打开团队协作的大门&#xff0c;推动项目稳步前行。 而那些真正厉害的项目经理&#xff0c;无一不是沟通的高手&#xff0c;他们通过清晰、有效且富有策略性的沟通&#xff0c;确保了项目的每一个环节都紧密…

小程序地图展示poi帖子点击可跳转

小程序地图展示poi帖子点击可跳转 是类似于小红书地图功能的需求 缺点 一个帖子只能有一个点击事件&#xff0c;不适合太复杂的功能&#xff0c;因为一个markers只有一个回调回调中只有markerId可以使用。 需求介绍 页面有地图入口&#xff0c;点开可打开地图界面地图上展…

x-cmd pkg | gotop - 简洁美观的终端监控工具,内存 CPU 网络 清晰可见

目录 简介用户首次快速实验指南友好的监控界面可定制化界面类似工具进一步探索 简介 gotop 是一个基于终端(TUI)的系统监视器。由 Andrew Gallant 于 2018 年 1 月发布。Andrew Gallant 在2020 年 8 月停止了对 gotop 的维护转由 Gregory Anders 维护和更新。 gotop 在终端使…

【ARM】armv8的虚拟化深度解读

Type-1 hypervisor Type-1虚拟化也叫做Bare metal, standalone, Type1 Type2 hypervisor Type-2虚拟化也叫做hosted, Type-2 VM和vCPU(虚拟机和虚拟cpu) 在一个VM&#xff08;虚拟机&#xff09;中有多个vCPU&#xff0c;多个vCPU可能属于同一个Vritual Processor。 EL2…

mysql如何快速编写单表查询语句

目录 背景生成sql语句 背景 我们在编写查询语句的时候&#xff0c;都提倡需要用到哪些字段就查哪些字段&#xff0c;这样有两个好处&#xff1a;1、可以增加程序运行效率&#xff0c;2、可以避免无关字段被暴露。那我们一个字段一个字段写就比较烦&#xff0c;有没有方法快速生…

Linux 进程3

进程地址空间 CPU读取数据都需要地址&#xff0c;在计算机中所有东西都是一种数据&#xff0c;包括我们的进程。 这是一个进程空间示意图&#xff0c;操作系统通过task_struct结构体链表来管理每一个进程&#xff0c;结构体里面有一个指针指向操作系统为进程开辟的一段空间&am…

共享单车轨迹数据分析:以厦门市共享单车数据为例(六)

副标题&#xff1a;.基于POI数据的站点功能混合度探究——以厦门市为例 为了保证数据时间尺度上的一致性&#xff0c;我们从互联网上下载了2020年的POI数据&#xff0c;POI数据来源于高德地图 API平台,包括名称、大小类、地理坐标等。并将高德地图 POI数据的火星坐标 系 GCJ-0…

目标检测系列(一)什么是目标检测

目录 一、相关名词解释 二、目标检测算法 三、目标检测模型 四、目标检测应用 五、目标检测数据集 六、目标检测常用标注工具 一、相关名词解释 关于图像识别的计算机视觉四大类任务&#xff1a; 分类&#xff08;Classification&#xff09;&#xff1a;解决“是什么&…

[附源码]宠物领养管理系统+SpringBoot

今天带来一款优秀的项目&#xff1a;宠物领养管理系统源码 。 系统采用的流行的前后端分离结构&#xff0c;内含功能包括"管理端"&#xff0c;“用户领养端”&#xff0c;“宠物管理”&#xff0c;“权限登录”等功能。 如果您有任何问题&#xff0c;也请联系小编&a…