多态--下

文章目录

      • 概念
      • 多态如何实现的指向谁调谁?
        • 例子
        • 分析
      • 含有虚函数类的大小是多少?
      • 虚函数地址
      • 虚表地址
      • 多继承的子类的大小怎么计算?
      • 练习题
      • 虚函数和虚继承

概念

优先使用组合、而不是继承;
继承会破坏父类的封装、因为子类也可以调用到父类的函数;
子类必须实现父类的纯虚函数;
内联函数没有地址,他是直接在定义的地方展开。所以不能是虚函数、虚函数是要有地址的;
虚函数不能是static函数,因为没有this指针、等于说是全局的,虚表要的是对象里面的;
普通函数继承是实现继承,就是不去重写父类的函数体,直接用的;虚函数的继承目的就是要重写这个函数体,自改成自己想要的;
虚函数在编译阶段就生成了,并且存在代码段;

析构函数最好写成多态。多态就是指向谁调谁,这样子类就可以调用自己的析构函数
构造函数不能写成多态;因为对象中的虚表指针实在初始化列表时开始初始化的;

多态如何实现的指向谁调谁?

虚函数的地址存在虚函数表中,通过虚函数表来调用虚函数;
同类型的对象共用一个虚表;
子类不重写父类的虚函数,也是和父类共用同一张虚表;重写就不会共用虚表

例子
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
using namespace std;

class person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人票" << endl;
	}
};

class student : public person
{
public:
	virtual void BuyTicket()
	{
		cout << "学生票" << endl;
	}
};


void buy(person& b)
{
	b.BuyTicket();
}


int main()
{
	student s;
	person p;
	buy(s);
	buy(p);
	return 0;
}
分析

1、子类继承后,虚函数表是一样的,重写后就把虚函数表copy出来换一个地址,把新的内容覆盖了;
image.png
2、调用时传过去的参数累心是谁的就指向谁的虚函数表,s是student类型那就是用student里面的函数;
image.png
2、子类虚函数不重写会怎样
如果不重写,那父级和子级虚函数表的地址是相同的
image.png

含有虚函数类的大小是多少?

普通函数不占空间,虚函数有个指针、所以站指针的大小空间,32位的4字节、64位的8字节;
在类里面:虚函数占一个指针的大小,不管有多少个虚函数就只占一个指针的大小;对象里面只是存了一个指针指向这个虚表
虚表的大小才要看有几个虚函数;
多继承的子类,继承了几个父类就有几个父类的指针大小
如下就一个虚函数64位
image.png
计算方法和结构体其实一样,内存对齐
加了一个int变量,理应8+4 = 12,但是最小对齐数为8,类的大小是其成员最小对齐数的整数倍;所以是16;
image.png

虚函数地址

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
using namespace std;

class person
{
public:
	virtual void BuyTicket()
	{
		cout << "成人票" << endl;
	}
private:
	int a;
};

class student : public person
{
public:
	virtual void BuyTicket()
	{
		cout << "学生票" << endl;
	}
};


void buy(person& b)
{
	b.BuyTicket();
}


class base
{
public:
	virtual void func1()
	{
		cout << "base::func1" << endl;
	}
private:
	int _b = 1;
};



void func()
{
	person b1;
	printf("vftptr:%p\n", *(int*) & b1);

	int i = 0;
	int* p1 = &i;
	int* p2 = new int;
	const char* p3 = "sad";
	printf("栈变量:%p\n", p1);
	printf("堆变量:%p\n", p2);
	printf("代码段常量:%p\n", p3);
	printf("代码段函数地址:%p\n", &base::func1);

}


int main()
{
	student s;
	person p;
	buy(s);
	buy(p);
	int size = sizeof(s);
	cout << size << endl;
	func();
	return 0;
}

问题:虚函数存在哪?虚函数表存在哪?
答:虚函数和普通函数都存在代码段、虚函数表也存在代码段
image.png
普通的函数、函数名就是地址(首地址)
成员函数的地址要加取地址符号&,以及要指定属于哪个类,也就是这样 &类名::函数名

虚表地址

class Base
{
public:
	virtual void fuc1(){cout << "fuc1" << endl;}
	virtual void fuc2(){cout << "fuc2" << endl;}
private:
	int a;
};

class derive : public Base
{
public:
	virtual void fuc1(){ cout << "fuc1111" << endl; }
	virtual void fuc3(){cout << "fuc3" << endl;}
};



typedef void(*VF_PTR)();//函数指针类型怎么写的
void PrintVFTable(VF_PTR* pTable)
{
	for(size_t i = 0; pTable[i] != 0; ++i)
	{
		printf("vfTable[%d]:%p->", i, pTable[i]);
		VF_PTR f = pTable[i];
		f();//运行函数
	}
	cout << endl;
}




int main()
{
	//student s;
	//person p;
	//buy(s);
	//buy(p);
	//int size = sizeof(s);
	//cout << size << endl;
	//func();

	derive a;
	Base b;
	PrintVFTable((VF_PTR*)(*(int*)&b));
	PrintVFTable((VF_PTR*)(*(int*)&a));

	return 0;
}

父类上面两行、子类为下面三行;
子类fuc1重写过了虚表地址就变了,没写fuc2但是继承了fuc2的虚表地址;
image.png
强转两次,(int*)是要取前4个字符,(VF_PTR*)强转函数指针
image.png
函数指针怎么写 void(*)()
type void(*a)(),这个a就代表函数指针了

多继承的子类的大小怎么计算?

继承几个父类就含有几个指针;

class Base1
{
public:
	virtual void fuc1() { cout << "b1:fuc1" << endl; }
	virtual void fuc2() { cout << "b1:fuc2" << endl; }
private:
	int a1;
};


class Base2
{
public:
	virtual void fuc1() { cout << "b2:fuc1" << endl; }
	virtual void fuc2() { cout << "b2:fuc2" << endl; }
private:
	int a2;
};

class derive2 : public Base1, public Base2
{
	virtual void fuc1() { cout << "b2:fuc1" << endl; }
	virtual void fuc3() { cout << "b2:fuc2" << endl; }

private:
	int a3;
};


int main()
{
	//student s;
	//person p;
	//buy(s);
	//buy(p);
	//int size = sizeof(s);
	//cout << size << endl;
	//func();

	//derive a;
	//Base b;
	//PrintVFTable((VF_PTR*)(*(int*)&b));
	//PrintVFTable((VF_PTR*)(*(int*)&a));

	cout << sizeof(derive2) << endl;
	derive2 a1;
	PrintVFTable((VF_PTR*)(*(int*)&a1));
	PrintVFTable((VF_PTR*)(*(int*)((char*)&a1 + sizeof(Base1))));

	return 0;
}

image.png
继承两个父类,两个指针的大小;
不同父类的虚表继承后不会共用;
derive2成员函数fuc3的虚表和Base1的虚表共用了,随机共用一个父类的虚表;

练习题

1、
image.png
2、
类中就只有变量、按顺序往下排;
p3是指向整块区域,所以首地址也是b1存的首地址;
p1也是b1存的首地址;
p2是b2的首地址;
所以选c;
image.png

虚函数和虚继承

image.png
是两个完全不同的概念;
用的都是virtual;

虚继承
image.png
菱形继承时,B、C继承A,D继承BC;

如上图使用虚继承,就会把公共的变量_a,放到一个地址上;
如果不用虚继承的话,就会有三个_a的地址;造成数据的冗余性;
二义性也是不用虚继承造成的,就是再回去找_a时,有很多_a;

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

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

相关文章

【OpenCV】图像像素的遍历

1 前言 介绍两种遍历像素的方法&#xff08;非指针、指针&#xff09;。注意&#xff1a;.at() .ptr()的作用、用法。相关API&#xff1a; Mat对象.ptr() Mat对象.at() 2 代码及内容 #include "iostream" #include "opencv2/opencv.hpp"using namespac…

知识图谱简介:探索知识的宇宙

知识图谱简介&#xff1a;探索知识的宇宙 一、引言 在这个由数据驱动的世界里&#xff0c;信息呈现出爆炸式的增长&#xff0c;人们对于管理和利用这些庞大数据量的需求也随之增长。知识图谱以其独特的方式&#xff0c;成为了整合和利用这些信息的有力工具。它不仅有助于组织杂…

小象超市(原美团买菜) 的大屏图表

文章目录 概要技术细节技术名词解释小结 概要 20203年12月1日&#xff0c;美团旗下自营零售品牌“美团买菜”升级为全新品牌“小象超市”。 &#xff0c;“小象超市”坚持美团自营零售模式&#xff0c;通过在社区设立的集存储、分拣、配送为一体的便民服务站&#xff0c;为社区…

ES8 学习 -- async 和 await / 对象方法扩展 / 字符串填充

文章目录 1. async 和 await1.1 基本语法1.2 使用示例1.3 案例练习 2. 对象方法扩展2.1 Object.values(obj)2.2 Object.entries(obj)2.3 Object.getOwnPropertyDescriptors(obj)使用示例 3. 字符串填充4. 函数参数的末尾加逗号 1. async 和 await async 函数&#xff0c;使得异…

Android Studio学习10——资源res的使用

一、String,StringArray的使用 一次修改&#xff0c;多出生效 String StringArray 二、color的使用 颜色代码对应表 和上面的相似用法 三、Dimen(尺寸)的使用 用的少&#xff0c;一般直接写尺寸 四、如何写一个drawable作为背景 五、如何写一个可以改变的drawable(按钮按下…

【合合TextIn】OCR身份证 / 银行卡识别功能适配鸿蒙系统

目录 一、 鸿蒙系统与信创国产化的背景 二、两款产品的兼容性升级详情 三、身份证产品介绍 四、银行卡识别产品 五、承诺与展望 一、 鸿蒙系统与信创国产化的背景 自鸿蒙系统推出以来&#xff0c;其不仅成为了华为在软件领域的重要里程碑&#xff0c;更是国产操作系统的一…

redis的键值基本操作

设置数据 首先设置键值对 删除age&#xff0c;会得到nil&#xff0c;表示这个键已经被删除掉了 判断age键还在不在 查找所有键 查找所有以me结尾的键 删除所有键 redis的键和值都是二进制存储的&#xff0c;所以默认不支持中文。 但是&#xff0c;我们重新登录客户端&#xff…

Java 变得越来越像 Rust?

随着编程技术的增强和复杂性的提升&#xff0c;许多编程语言也纷纷效仿&#xff0c;Java 也不例外。 另一边&#xff0c;尽管社区内部问题重重&#xff0c;但 Rust 仍逐年获得开发人员的喜爱。这背后都是有原因的&#xff1a;Rust 的编译器让开发人员避免了各种问题。编译器对…

【JavaScript】JS高级语法

目录 1.变量与函数 1.1作用域 1.2定义变量 1.3作用域链 1.4闭包 1.5预解析 1.6let提升 1.7函数参数 1.8箭头函数 2.解构赋值 3.1数组解构 3.2对象解构 3.对象 4.1字面量创建对象 4.2构造函数 4.2.1自定义构造函数 4.2.2静态成员和实例成员 4.数据类型 4.1引…

绿联 安装phpmyadmin管理MySQL数据库

绿联 安装phpmyadmin管理MySQL数据库 1、镜像 phpmyadmin:latest 2、安装 2.1、基础设置 重启策略&#xff1a;容器退出时总是重启容器。 2.2、网络 网络选择桥接&#xff08;bridge&#xff09;。 2.3、存储空间 可增加配置文件&#xff0c;一般无需添加&#xff0c;不做…

【教学类-09-07】20240401细线迷宫图02+箭头图片(A4横版一页-2份竖版)

作品展示 作品展示 word模板 重点说明 代码展示 批量制作细线条的迷宫图(A4横板一面2张竖版)箭头图片 作者&#xff1a; 1、落难Coder https://blog.csdn.net/u014297502/article/details/124839912 2、AI对话大师 3、阿夏 作者&#xff1a;2024年4月3日 numint(input(几人&…

《数据结构学习笔记---第九篇》---循环队列的实现

文章目录 1.循环队列的定义 2.循环队列的判空判满 3.创建队列并初始化 4.入队和出队 5. 返回队尾队首元素 6.释放循环队列 1.循环队列的定义 定义&#xff1a;存储队列元素的表从逻辑上被视为一个环。 我们此次实现的循环队列&#xff0c;采用顺序表 typedef struct {int…

OpenCv —— cv::VideoCapture设置摄像头图像格式为“MJPEG“

背景 今天恰巧同事有台USB摄像头,她想要在Windows系统下通过OpenCV读取该摄像头宽高为1080x768、帧率为60的视频,用来做图像算法处理。但无奈通过网上OpenCV教程 读取的视频对应尺寸的帧率仅为10帧左右,根本无法满足使用要求。于是作者通过本篇文章介绍如何解决,欢迎交流指…

Word的”交叉引用“和”插入题注“快捷键设置

Word的”交叉引用“和”插入题注“快捷键设置 在MSWord2021中&#xff0c;可以自定义设置快捷键。方法如下&#xff1a;文件-选项-自定义功能区-键盘快捷方式&#xff08;自定义&#xff09;。具体过程如图所示。 最后&#xff0c;按照上述流程将插入题注&#xff08;Insert…

Somme Requiem 全AI制作的电影短片

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Linux基础概念

Linux Linux 和 UNIX 中的文件系统是一个以 / 为根的树状式文件结构&#xff0c;/ 是 Linux 和 UNIX 中的根目录&#xff0c;同样它也是文件系统的起点。所有的文件和目录都位于 / 路径下&#xff0c;包括经常听到的 /usr、/etc、/bin、/home 等。在早期的 UNIX 系统中&#x…

格式化输出数据

JDK 5 新特性&#xff0c;格式化输出数据 长度不够前面补空格&#xff0c;超出长度按实际输出 System.out.printf(“格式控制部分”,表达式1,表达式2,,表达式n); 格式控制部分由格式符号、普通字符组成&#xff0c;普通字符原样输出&#xff0c;格式符号输出表达式的值 // …

03 | Swoole 源码分析之 Http Server 模块

首发原文链接&#xff1a;Swoole 源码分析之 Http Server 模块 大家好&#xff0c;我是码农先森。 Http 模块的注册初始化 这次我们分析的就是 Swoole 官网的这段代码&#xff0c;看似简单&#xff0c;实则不简单。 在 Swoole 源码文件 swoole_http_server.c 中有这样一个函数…

银行监管报送系统介绍(十五):金融审计平台

《“十四五”国家审计工作发展规划》中重点强调&#xff0c;金融审计&#xff1a;以防范化解重大风险、促进金融服务实体经济&#xff0c;推动深化金融供给侧结构性改革、建立安全高效的现代金融体系为目标&#xff0c;加强对金融监管部门、金融机构和金融市场运行的审计。 —…

用于自动驾驶,无人驾驶领域的IMU六轴陀螺仪传感器:M-G370

用于自动驾驶,无人驾驶的IMU惯导模块六轴陀螺仪传感器:M-G370。自2020年&#xff0c;自动驾驶,无人驾驶已经迎来新突破&#xff0c;自动驾驶汽车作为道路交通体系的一员&#xff0c;要能做到的就是先判断周边是否有障碍物&#xff0c;自身的行驶是否会对其他交通参与成员产生危…