part-01 C++知识总结(程序的内存分区、多态的实现)

news2024/11/26 19:20:00

总结来自:拓跋阿秀大佬的面试知识网站,侵权删

一.程序的内存分区/程序模型

        内存分区分别是堆、栈,自由存储区,全局/静态存储区、常量存储区和代码存储区。

 :在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集里面,效率很高,但是分配的内存容量有限。

:就是哪些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。

自由存储区:如果说堆是操作系统维护的一块内存,那么自由存储区就是C++中通过new和delete动态分配和释放对象的抽象概念。需要注意的是,自由存储区和堆比较像,但不等价。

全局/静态存储区:全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量和静态变量又分为初始化的和未初始化的,在C++中没有这个区分,它们共占同一块内存区,在该区定义的变量若没有初始化,则会被自动初始化,例如int型变量自动初始化为0。

常量存储区:这是一块比较特殊的存储区,这里面存放的是常量,不允许修改。

代码区:存放函数体的二进制代码。

二.多态的实现

        在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据所指对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函数。

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
};
class C :public A {
public:

};
int main() {
	A *b = new B();
	b->prints();
	b = new C();
	b->prints();
	return 0;
}

 子类B重写了基类A的虚函数,子类C并没有重写,从结果分析,依然是体现了多态性???

虚表和虚基表指针

要理解这个问题,我们要引出虚表和虚基表

虚表:虚函数表的缩写,类中含有 virtual 关键字修饰的方法时,编译器会自动生成虚表,它是在编译器确定的

虚表指针:在含有虚函数的类实例化对象时,对象地址的前四个字节存储的指向虚表的指针,它是在构造函数中被初始化的

上图就是虚表和虚表指针在基类对象和派生类对象中的模型,下面阐述实现多态的过程:

1.编译器在发现基类中含有虚函数时,会自动为每个含有虚函数的类生成一份虚表,该表是一个一维数组,虚表里保存了虚函数的入口地址

2.编译器会在每个对象的前四个字节中保存一个虚表指针,即vptr,指向对象所属类的虚表

3.所谓的合适时机,在派生类定义对象时,程序运行会自动调用构造函数,在构造函数中创建虚表并对虚表指针进行初始化。在构造子类对象时,会先调用父类的构造函数,此时,编译器只“看到了”父类,并为父类对象初始化虚表指针,令它指向父类的虚表;当调用子类的构造函数时,为子类对象初始化虚表指针,令它指向子类的虚表

4.当派生类对基类的虚函数没有重写时,派生类的虚表指针指向的是基类的虚表;当派生类对基类的虚函数重写时,派生类的虚表指针指向的是自身的虚表;当派生类中有自己的虚函数时,在自己的虚表中将此虚函数地址添加在后面。

所以,指向派生类的基类指针在运行时,就可以根据派生类对虚函数的重写情况动态的进行调用,从而实现多态性。 

三.为什么析构函数一般写成虚函数?

        由于类的多态性,通常通过父类指针或引用来操作子类对象。因为多套允许我们以统一的方式处理不同的派生类对象,并且在运行时确定要调用的方法。

        如果析构函数不被声明为虚函数,则编译器实施静态绑定,在删除基类指针时,只会调用基类的析构函数而不调用派生类析构函数,这样会造成派生类析构不完全,造成内存泄漏。

        这种行为是为了确保资源的正确释放。由于我们只知道父类的类型,编译器无法确定指针指向的是哪个子类对象,因此只能调用父类的析构函数来释放资源。

没有虚析构:

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
	virtual ~A() {
		cout << "A:析构函数 " << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
	~B() {
		cout << "B:析构函数 " << endl;
	}
};
int main() {
	A *b = new B();
	b->prints();
	delete b;
	b = NULL;
	return 0;
}

虚析构:

#include<iostream>
#include<vector>
using namespace std;
class A {
public:
	virtual void prints() {
		cout << "A::prints" << endl;
	}
	A() {
		cout << "A:构造函数" << endl;
	}
	virtual ~A() {
		cout << "A:析构函数 " << endl;
	}
};
class B:public A {
public:
	virtual void prints() {
		cout << "B::prints" << endl;
	}
	B() {
		cout << "B:构造函数" << endl;
	}
	~B() {
		cout << "B:析构函数 " << endl;
	}
};
int main() {
	A *b = new B();
	b->prints();
	delete b;
	b = NULL;
	return 0;
}

 

分析:可以看到析构函数是,先从子类析构,再到父类析构 

四.sort()函数中的排序函数是快排还是插入排序?

        sort()源码中采用的是 IntroSort内省式排序的混合式排序算法。

第一步:

  • 首先进行判断排序的元素是否大于 stl_threshould ,stl_thresould是一个常量值是16,意思是说我传入的元素规模小于16的时候直接采用插入排序。
  • (为啥呢?因为插入排序在面对“几近排序”的序列时,表现更好,而快排是通过递归实现的,会为了极小的子序列产生很多的递归调用,在区间长度小的时候经常不如插入排序效率高)

第二步:

  • 如果说我们的元素规模大于16,那就需要判断是不是能采用快速排序,如何判断呢?
  • 快排是使用递归来实现的,如果说我们进行判断我们的递归升读有没有到达递归升读的限制阈值 2*lg(n) ,如果递归深度没到达就使用快速排序。

第三步:

  • 如果说大于我们的最深递归深度阈值的话,这个时候说明快排复杂度退化了(比如很不巧基准元素多次选取到了当前区间中最小或最大的元素,这种情况下,每次划分只能将区间缩小1个元素,造成递归深度过深)
  • 此时采用堆排序,堆排序是可以保证稳定 O(nlogn) 的时间复杂度的。

五.STL中map、set、unordered_set、unordered_map的区别和应用场景

map

        map支持键值的自动排序,底层机制是红黑树,红黑树的查询和维护时间复杂度均为 O(logn) ,但是占用空间比较大,因为每个节点都要保持父节点、孩子节点及颜色信息。

set

        set与map类似,set的底层实现通常也是红黑树。set是一种特殊的Map,只有键没有值。

unordered_map 

        unordered_map是C++ 11 新添加的容器,底层机制是哈希表,通过hash函数计算元素位置,其查询时间复杂度为 O(1) ,维护时间与 buclet 桶所维护的 list 长度有固安,但是建立 hash 表耗时较大。

unordered_set

        unordered_set与unordered_map 类似,unordered_set的底层实现通常也是哈希表。unordered_set 是一种特殊的unordered_map,只有键没有值。

从底层机制和特点可以看出:map适用于有序数据的应用场景,unordered_map适用于高效查询的应用场景。

六.move用过吗?(不太明白)

C++中的move语义是一种高效的资源转移机制,可以帮助我们避免不必要的拷贝操作,提高程序性能。

std::move 的使用场景

当需要将资源从一个对象转移到另一个对象时,可以使用std::move。例如,在容器中移动元素,在算法中交换数据等。需要注意的是,只有可移动的对象才能使用移动语义,否则可能导致未定义行为。(比如容器加了const,无法修改)

避免不必要的拷贝

使用移动语义可以避免不必要的拷贝操作,从而提高性能。例如,在复制一个大型对象时,如果使用移动语义,只需要进行一次内存分配和一次指针拷贝,而不需要进行多次拷贝操作。

移动构造函数:move可以将一个左值转换为右值引用,从而实现资源转移

移动赋值运算符:move也可以用于将一个对象的资源转移到另一个对象

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

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

相关文章

centos升级python3.10,中间遇到问题,终于解决了

升级为python3.10 yum updateyum install openssl-devel bzip2-devel libffi-develyum groupinstall "Development Tools"wget https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tgztar -xzf Python-3.10.2.tgzcd Python-3.10.2./configure --enable-optimi…

OpenCV(九):LUT查找表

LUT&#xff08;Look-Up Table&#xff09;查找表是OpenCV中一种常用的图像处理方法&#xff0c;用于对图像进行像素级别的颜色映射或图像增强操作。LUT查找表可以实现快速、高效的颜色转换和像素操作&#xff0c;尤其在处理大量像素的情况下具有优势。以下是关于OpenCV LUT查找…

王传福猛男落泪,比亚迪疯狂赚钱

作者&#xff5c;丁广胜 出品&#xff5c;网易科技智见焦点 厮杀告一段落&#xff0c;成绩揭晓。 降价、吵架、还有眼泪&#xff0c;充斥在这略显漫长的2023上半年。 先看一组数据&#xff0c;上半年比亚迪新能源汽车销售151.78万辆&#xff0c;特斯拉是54万辆、理想汽车是14万…

英国选校8.27|8.29

目录 IC帝国理工学院 UCL伦敦大学学院 ​编辑 Band A B C 专业院系 爱丁堡 曼彻斯特 KCL伦敦国王学院 Bristol布里斯托 华威 南安普顿 IC帝国理工学院 UCL伦敦大学学院 24qs专业位置双非雅思气候备注9 MSc Scientific and Data Intensive Computing MSc Urban Sp…

阔别线下三年的BIRTV影视盛会:有哪些变革式创新应用?

2023年8月26日&#xff0c;以“融合创新 面向未来”为主题的第三十届北京国际广播电影电视展览会&#xff08;BIRTV 2023&#xff09;收官。这是一场阔别线下三年的行业顶尖盛会&#xff0c;展馆处处人潮涌动。 接下来盘点一下&#xff0c;本次BIRTV的一些特色应用&#xff1a…

司徒理财:8.30黄金日内高空,随后回调看涨

黄金走势分析&#xff1a; 从日线形态来看&#xff0c;昨晚经历了快速拉升&#xff0c;价格成功稳定在关键的1924压力位之上&#xff0c;最高甚至触及了1938的高点。这表明市场开启了新一轮走势的空间。在当天的日内交易中&#xff0c;我们应特别关注1924一线作为支撑&#xff…

远传水表数据是怎么远传的?

随着科技的不断发展&#xff0c;智慧城市的建设逐渐成为城市发展的重要方向&#xff0c;而智能水表作为智慧城市中的重要组成部分&#xff0c;它的数据远传功能更是给水务管理带来了极大的便利。下面就由在智能水电表行业摸爬滚打多年的小编来为大家讲解下吧! 一、远传水表数据…

SLAM从入门到精通(基础数学)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 不可否认&#xff0c;slam中的有一部分内容来自于数学。但是&#xff0c;我们在学习使用的过程中&#xff0c;也不用纠结于整个数学的推导过程&…

营收纯利双增长,朝云集团通过了消费品市场的层层筛选

8月28日晚&#xff0c;朝云集团发布了一份惊喜的半年报。 上半年&#xff0c;公司收入11.33亿元&#xff0c;同比增长10.7%&#xff1b;纯利1.36亿元&#xff0c;同比增长51.7%&#xff0c;毛利率同比增长2.2个百分点。 上半年整体消费活跃&#xff0c;对朝云集团的一系列消费…

day 43 | ● 123.买卖股票的最佳时机III ● 188.买卖股票的最佳时机IV

123.买卖股票的最佳时机III func maxProfit(prices []int) int {dp : make([][]int , len(prices))dp[0] []int{0, -prices[0], 0, -prices[0], 0}for i : 1; i < len(prices);i{val0 : dp[i - 1][0]val1 : max(dp[i - 1][0] - prices[i], dp[i - 1][1])val2 : max(dp[i - …

Overleaf,MDPI模板,参考文献,BibTex转换为bibitem格式

①&#xff1a;新建文件ref.bib。 ②&#xff1a;将BibTex格式的参考文献考入ref.bib中&#xff08;红框中的文字后面有用&#xff0c;此处先不用管&#xff09;。 ③&#xff1a;在template.tex文件中&#xff0c;直接将整个{thebibliography}部分从begin到end全部删除。 ④&a…

什么是自动语音识别?

在人工智能发展和全球疫情的双重作用下&#xff0c;企业加强了与客户的线上沟通。企业越发依赖于虚拟助手、聊天机器人以及其他的语音技术&#xff0c;以实现与客户的高效互动。这几类人工智能&#xff0c;都是依赖于自动语音识别技术&#xff0c;简称为ASR。ASR涉及到将语音转…

初识Redis之分布式

一.简单介绍: Redis是用来在内存中, 存储数据的, 他的初心是用来搞消息中间件(或者说消息队列 很熟悉了吧~~),但是呢用的不多,他现在主要是用来做 数据库,缓存 用来存储数据, 为什么不直接存储呢? Redis的优势就在于分布式系统 二.分布式系统 要说其分布式系统,简单想想都能…

相同二叉树判断

目录 题目题目要求示例 解答方法一、实现思路时间复杂度和空间复杂度代码 方法二、实现思路时间复杂度和空间复杂度代码 题目 相同二叉树判断 题目要求 题目链接 示例 解答 方法一、 递归 实现思路 如果两棵树从根结点一起访问&#xff0c;当有一个结点不相等时就返回f…

MindSponge分子动力学模拟——定义一个分子系统(2023.08)

技术背景 在前面两篇文章中&#xff0c;我们分别介绍了分子动力学模拟软件MindSponge的软件架构和安装与使用教程。这里我们进入到实用化阶段&#xff0c;假定大家都已经在本地部署好了基于MindSpore的MindSponge的编程环境&#xff0c;开始用MindSponge去做一些真正的分子模拟…

版本控制 Git工具的使用

版本控制的概念&#xff1a; 版本控制&#xff08;Revision control&#xff09;是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史&#xff0c;方便查看更改历史记录&#xff0c;备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理多人协同开发…

Nacos使用(中):Java项目和Spring项目使用Nacos

Nacos使用(上)&#xff1a;Nacos安装 Nacos使用(中)&#xff1a;Java项目和Spring项目使用Nacos Nacos使用(下)&#xff1a;SpringBoot和SpringCloud项目中使用Nacos 3.使用Nacos 3.1 java SDK 引入jar包 <dependency><groupId>com.alibaba.nacos</groupId>…

Android集成Unity,实现3D看房效果

引子 前几天有人找小编问能不能把3D模型放入到Unity中&#xff0c;再把Unity放入到Android APP中&#xff0c;在APP中实现观看房屋家具的功能&#xff0c;这次小编便来分享一下吧&#xff0c;如果还需要了解Android 集成Unity知识的&#xff0c;可以翻我主页其他文章 演示效果…

为什么关键词优化很重要,以及如何进行网络营销?

随着互联网的发展&#xff0c;越来越多的企业开始将重心放在网络营销上。在网络营销中&#xff0c;关键词优化是一个非常重要的环节。本文一秒推小编将介绍什么是关键词优化&#xff0c;为什么关键词优化很重要&#xff0c;以及如何进行关键词优化。 一、什么是关键词优化&…

性能瓶颈分析及调优

分析流程&#xff1a; 很多情况下压测流量并没有完全进入到后端&#xff08;服务端&#xff09;&#xff0c;在网络接入层&#xff08;云化的架构比如&#xff1a;SLB/WAF/高防IP&#xff0c;甚至是CDN/全站加速等&#xff09;可能就会出现由于各种规格&#xff08;带宽、最大…