C++/STL
文章平均质量分 73
C++
liufeng2023
日拱一卒
展开
-
456-C++函数重载机制(汇编层面分析)
举例: overload.cc上面print(12)会去调用print(int),print(“hello world”)会去调用print(string)。如下面的结果:(先用编译,然后执行)为了了解编译器是如何处理这些重载函数的,我们反编译下上面我们生成的执行文件,看下汇编代码(全文都是在Linux下面做的实验)。我们执行命令反汇编并将结果重定向到log.txt 文件中,然后分析 log.txt 文件。1、发现函数void print(int i)编译之后为:(注意它的函数签名变为——_Z5pri原创 2022-07-04 19:23:12 · 159 阅读 · 0 评论 -
455-C++ 多态(知乎)
多态性(polymorphism)可以简单地概括为:“一个接口,多种方法”,它是面向对象编程领域的核心概念。C++支持两种多态性:多态与非多态的实质区别:如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。多态的目的:多态最常见的用法:需要注意:重写有两种:重载:隐藏:隐藏规则如下:举例:有virtual才可能发生多态现象,不发生多态(无virtual)调用就按原类型调用 。上面的原创 2022-07-04 10:48:01 · 205 阅读 · 0 评论 -
453-atoi函数的实现
作用:参数:返回值:测试:测试结果:2、自己实现atoi函数1、如果参数字符串以数字开头,则一直往后读,直到读到非数字字符或\0。然后将这些数字以整数形式返回。如:,返回整数。,返回整数。2、如果参数字符串以正负号开头,则往后读取,如果紧接着读到数字,此时与(1)相同。只是在返回整数时要加正负号。如果正负号后面不是数字字符,则返回0。如:,返回。,返回。和返回。3、如果参数字符串以空格字符开头(\n,\r,\t,\f,\v),则跳过空格字符,再按照(1)和(2)进行判断。如:,返回。4、如果不是以原创 2022-07-02 15:38:35 · 136 阅读 · 0 评论 -
452-strcpy、strcat、strcmp、strstr、strchr的实现
作用:思路:2、strcat函数作用:思路:3、strcmp函数作用:思路:4、strstr函数作用:5、strchr函数作用:原创 2022-07-02 14:57:38 · 91 阅读 · 0 评论 -
451-memcpy、memmove、memset的实现
和都是C语言中的库函数,包含于头文件中。memcpy的作用:作用:下面举个例子说明一下内存重叠是什么意思:原创 2022-07-02 14:08:37 · 195 阅读 · 0 评论 -
449-原码、补码、反码
所以接下来我们需要来了解一下原码、反码和补码。机器数:机器数的真值:原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值,例如的十进制的的正负1,用8位二进制的原码表示如下:【+1】= 原:[ 0000 0001 ]【-1】= 原:[ 1000 0001 ]反码的表示方法为:【+1】= 原: [ 0000 0001 ] = 反:[ 0000 0001 ]【-1】 = 原:[ 1000 0001 ] = 反:[ 1111 1110 ]补码的表示方法为:计算机实际只存储补码;所以原码转换为补码的原创 2022-07-01 21:37:26 · 102 阅读 · 0 评论 -
448-Linux生成可执行程序的过程
你知道一次gcc命令究竟经历了什么吗?我们先来看一段C语言示例源代码:编译运行:如图一:我们平时都会使用gcc来编译程序,这一行简单的命令其实经历了很多复杂的过程:首先使用file看一下test.cc文件类型:我们接下来看看这每个过程都做了什么?命令:再看下test.i的文件类型:这里可以看出预处理后的文件和预处理前的文件类型是相同的,都是文本文件,也可以直接查看test.i的内容,里面代码较多,就不贴上来了。预处理主要操作有这几个:命令:再查看文件类型:如图二,编译过程就是把预处理后原创 2022-07-01 20:06:05 · 99 阅读 · 0 评论 -
424-计算机网络(14-17)
OSI 体系结构: 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。TCP/IP体系结构: 网络接口层、网际层IP、传输层、应用层。物理层: 通过媒介传输比特,确定机械及电气规范(比特Bit)数据链路层: 将比特组装成帧和点到点的传递(帧Frame)网络层: 负责数据包从源到宿的传递和网际互连(包PackeT)传输层: 提供端到端的可靠报文传递和错误恢复(段Segment)会话层: 建立、管理和终止会话(会话协议数据单元SPDU)表示层: 对数据进行翻译、加密和压缩(表示协议数据单元原创 2022-06-25 19:58:24 · 536 阅读 · 0 评论 -
412-C++中map自定义key和value排序
map默认是按key值从小到大排序的map容器里面有两个值一个key一个是value,,其实map里面还有第三个参数,是一个类,用来对map的key进行排序的类,定义如下:less的代码:那么根据上面的代码我们也可以写出一个greater类来让key按照降序排列:注意:这里也可以不使用MyCompare 仿函数,直接用greater将map的key和value以pair的形式装到vector中,对vector进行排序。 (下面使用unordered_map,而没有使用map)这是从小......原创 2022-06-23 12:49:38 · 569 阅读 · 0 评论 -
347-C++多继承下,派生类对象有几张虚函数表?
我们看下面这个示例:运行截图:C++多继承下,派生类对象有几张虚函数表?我们打开VS编译器的工具下的命令行,进入代码目录;执行:派生类对象有3个虚函数指针,三个虚函数表,分别对应于三个基类。...原创 2022-06-11 09:44:34 · 480 阅读 · 0 评论 -
346-C++ this指针
类的成员函数可以访问类的数据(限定符只是限定于类外的一些操作,类内的一切对于成员函数来说都是透明的);那么成员函数如何知道哪个对象的数据成员要被操作呢?注意:在 C++ 中,每一个对象都能通过 this 指针来访问自己的地址。this 指针是所有成员函数的隐含参数。因此,在成员函数内部,它可以用来指向调用对象。成员函数默认第一个参数为。(友元函数,全局函数不是成员函数)静态函数如同静态变量一样,他不属于具体的哪一个对象,静态函数表示了整个类范围意义上的信息,而this指针却实实在在的对应一个对象,所以thi原创 2022-06-11 09:30:39 · 56 阅读 · 0 评论 -
345-C++11 decltype类型推导
decltype 是 C++11 新增的一个关键字,它和 auto 的功能一样,都用来在编译时期进行自动类型推导。既然已经有了 auto 关键字,为什么还需要 decltype 关键字呢?auto 和 decltype 关键字都可以自动推导出变量的类型,但它们的用法是有区别的:其中,varname 表示变量名,value 表示赋给变量的值,exp 表示一个表达式。另外 ,auto 要求变量必须初始化,而 decltype 不要求。 这很容易理解,auto 是根据变量的初始值来推导出变量类型的,如果不初始原创 2022-06-10 10:10:51 · 91 阅读 · 0 评论 -
342-C++标准异常的基类exception
C++语言本身或者标准库抛出的异常都是 exception 的子类,称为标准异常(Standard Exception)。你可以通过下面的语句来捕获所有的标准异常:之所以使用引用,是为了提高效率。如果不使用引用,就要经历一次对象拷贝(要调用拷贝构造函数)的过程。exception 类位于 < exception > 头文件中,它被声明为:这里需要说明的是 what() 函数。what() 函数返回一个能识别异常的字符串,正如它的名字“what”一样,可以粗略地告诉你这是什么异常。不过C++标准并没有规定原创 2022-06-10 09:11:33 · 539 阅读 · 0 评论 -
341-C++异常类型以及多级catch匹配
首先来回顾一下上篇博客讲到的 try-catch 的用法:我们还遗留下一个问题,就是 catch 关键字后边的exceptionType variable,这节就来详细分析一下。是异常类型,它指明了当前的 catch 可以处理什么类型的异常;是一个变量,用来接收异常信息。当程序抛出异常时,会创建一份数据,这份数据包含了错误信息,程序员可以根据这些信息来判断到底出了什么问题,接下来怎么处理。异常既然是一份数据,那么就应该有数据类型。C++ 规定,异常类型可以是 int、char、float、bool 等基本原创 2022-06-10 08:54:48 · 243 阅读 · 0 评论 -
340-C++异常处理(try catch)
大致可以分为三种,分别是语法错误、逻辑错误和运行时错误:运行代码,在控制台输出 ch1 的值后程序崩溃。下面我们来分析一下原因:我们可以借助 C++ 异常机制来捕获上面的异常,避免程序崩溃。捕获异常的语法为:try和catch都是 C++ 中的关键字,后跟语句块,不能省略{ };try 中包含可能会抛出异常的语句,一旦有异常抛出就会被后面的 catch 捕获;从 try 的意思可以看出,它只是“检测”语句块有没有异常,如果没有发生异常,它就“检测”不到;catch 是“抓住”的意思,用来捕获原创 2022-06-10 08:33:22 · 2584 阅读 · 0 评论 -
336-建议用make_shared代替shared_ptr
我们先看下面的代码:对于sp1来说,它的内存布局如下:shared_ptr是继承的_Ptr_base类:我们进入_Ptr_base类中::表示强智能指针使用这个资源的计数!:表示弱智能指针使用这个资源的计数!转换成图解如下:只有uses从1减到0,智能指针shared_ptr才能析构释放其所指向的资源。这样子,确实是存在缺陷!!!这句代码,存在2个内存开辟:那么,我们继续看下面代码:拿sp1拷贝构造sp2按理说,uses会加1,因为又有一个强智能指针指向这个资源。拿一个弱智能指针监视观原创 2022-06-08 16:12:35 · 263 阅读 · 0 评论 -
329-C++的RAII机制
上面说到RAII是用来管理资源、避免资源泄漏的方法。那么,用了这么久了,也写了这么多程序了,口头上经常会说资源,那么资源是如何定义的?在计算机系统中,资源是数量有限且对系统正常运行具有一定作用的元素。比如:网络套接字、互斥锁、文件句柄和内存等等,它们属于系统资源。由于系统的资源是有限的,就好比自然界的石油,铁矿一样,不是取之不尽,用之不竭的。所以,我们在编程使用系统资源时,都必须遵循这几个步骤:第一步和第二步缺一不可,因为资源必须要申请才能使用的,使用完成以后,必须要释放,如果不释放的话,就会造成资源泄漏。原创 2022-06-06 22:21:34 · 73 阅读 · 0 评论 -
317-C++设计模式(观察者Observer模式)
## 1、观察者Observer模式- 观察者模式是行为型模式;- **行为型模式:** 主要关注的是对象之间的通信- 观察者模式又叫做观察者(Observer)监听者(Listener)模式,也叫发布(Publish)订阅(Subscribe)模式- **主要关注的是对象的一对多的关系,也就是多个对象都依赖一个对象,当该对象的状态发生改变时,其它对象都能够接收到相应的通知。**原创 2022-06-02 17:52:56 · 115 阅读 · 0 评论 -
316-C++设计模式(适配器模式)
适配器模式: 让不兼容的接口可以在一起工作举个例子:假如我们有VGA接口的电脑, 刚好(TV)投影仪也是VGA接口(此时电脑上的视频可以直接投到投影仪上):原创 2022-06-02 12:54:28 · 64 阅读 · 0 评论 -
312-C++设计模式(装饰器模式)
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。目的: 为了增强现有类的功能。因此我们使用装饰器模式!和代理模式很像,只不过装饰器会对装饰的对象进行功能的扩展!原创 2022-06-01 16:10:53 · 103 阅读 · 0 评论 -
309-C++设计模式(代理模式)
1、结构型模式(代理模式 & 适配器模式)这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。2、代理模式不是所有的客户都能访问到老板,老板的助理,即通过代理类,来控制实际对象的访问权限。代理类和委托类是组合关系!!!#include <iostream>#include <memory>using namespace std;/*代理Proxy模式 : 通过代理类,来控制实际对象的访问权限客户 助理Pr原创 2022-05-31 15:07:35 · 75 阅读 · 0 评论 -
306-C++设计模式(抽象工厂)
1、工厂方法缺点仔细理解前面的工厂方法模式,会发现一个问题,就是每一个实例工厂负责生产一个实例产品,也就是一个产品对应一个工厂,一个工厂对应一个产品,那么小米不仅仅生产手机,还生产耳机,智能手环,智能插座等等相关的小米产品簇,不可能给这每一个产品都创建一个工厂类,那样的话代码中的类就太多了,不好维护, 而且也不符合实际情况。实际上小米或者华为的工厂里面,有相关联的产品簇都是在一个工厂完成创建的;BMW或者Audi汽车制造工厂除了生产汽车,生产线上也有可能生产轮胎,或者其它的汽车附属产品。原创 2022-05-30 21:03:01 · 69 阅读 · 0 评论 -
299-C++设计模式( 简单工厂 & 工厂方法)
简单工厂 & 工厂方法工厂分为:简单工厂(Simple Factory) 不属于标准的OOP设计模式中的一项,工厂方法和抽象工厂是属于标准的23种设计模式的;1、Simple Factory简单工厂简单工厂(Simple Factory) 不属于标准的OOP设计模式中的一项;在编写大型C++软件的时候,代码里面会出现很多的类,**每次创建对象的时候,都需要通过new 类名称的方式来生成对象,这样一来,用户需要记忆很多类的名称,暂且不管记不记得住,这样的设计使得代码很难维护,**类名原创 2022-05-29 22:18:08 · 119 阅读 · 0 评论 -
288-C++设计模式(单例模式)
设计模式概念设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,与我们自己摸索出来的问题解决之道相比较,有以下优点可取:代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好;当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够做到软件设计要求的“开-闭原则”,即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活;合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的根本原则“高内聚,低耦合”因此掌握常用的设计模式非原创 2022-05-25 15:41:51 · 230 阅读 · 0 评论 -
250-C++泛型算法和绑定器
C++泛型算法和绑定器1、C++泛型算法#include <algorithm>//包含了C++ STL里面的泛型算法泛型算法 = template + 迭代器 + 函数对象特点一: 泛型算法的参数接收的都是迭代器(因为泛型算法是给所有容器都可以应用的,所以要有特定统一的方式,把所有容器类型元素遍历,所以是迭代器)特点二: 泛型算法的参数还可以接收函数对象(C函数指针)sort,find,find_if,binary_search,for_each 所有容器都可以使用2、绑原创 2022-05-20 10:35:58 · 74 阅读 · 0 评论 -
82-C++函数对象
1、C函数和函数对象C++ 函数对象 => C语言里面的函数指针这是2个函数调用,看起来一模一样的。实际上有区别:sum在左边代码块是地址,函数名,在右边代码块是对象。我们把有operator()小括号运算符重载函数的对象,称作函数对象,或者称作仿函数2、使用函数对象的好处上面这个函数不灵活,有的时候我们也想要它们比较小于,或者比较大于又要比较小于。1、使用C的函数指针的解决方案#include <iostream>using namespace std;原创 2022-04-26 16:20:34 · 1086 阅读 · 0 评论 -
247-C++STL(迭代器)
C++STL(迭代器)顺序容器和关联容器,都支持正向迭代器和反向迭代器!const_iterator: 常量的正向迭代器,只能读,而不能写了iterator: 普通的正向迭代器,从第一个访问到最后一个,可以更改元素值reverse_iterator: 普通的反向迭代器const_reverse_iterator: 常量的反向迭代器,只能解引用读取元素的值,不能修改元素的值1、正向迭代器:iterator普通的正向迭代器iterator既可以读又可以修改容器的元素。2、常量迭代器原创 2022-05-19 20:36:10 · 79 阅读 · 0 评论 -
246-C++STL(关联容器)
关联容器关联容器:1、各个容器底层的数据结构 O(1) /O(log2n)2、常用增删查方法增加: insert(val)遍历: iterator自己搜索, 调用find成员方法删除: erase(key) erase(it)1、无序关联容器无序关联容器 =>底层实现是 链式哈希表 增删查的时间复杂度O(1)set:集合,存储 keymap:映射表,存储 [key,value]键值对unordered_set 无序的单重集合unordered_multiset无序的 多重集合原创 2022-05-19 17:37:55 · 294 阅读 · 1 评论 -
245-C++STL(容器适配器)
C++STL(容器适配器)标准容器 - 容器适配器 => 我们有一种设计模式,就叫做适配器模式怎么理解这个适配器?适配器底层没有自己的数据结构,它是另外一个容器的封装,它的方法全部由底层依赖的容器进行实现的!没有实现自己的迭代器(在栈里放一堆元素,不能用迭代器去遍历这些元素,因为根本没有实现迭代器)我们查看下STL的stack源码:_Container: 定制的容器,用户可以不用传,默认是使用deque成员变量就是用_Container定义了一个容器!里面的方法都是用的_Co原创 2022-05-19 16:03:37 · 119 阅读 · 0 评论 -
237-C++STL(vector、deque、list对比)
1、vector、deque、list对比vector特点:动态数组,内存是连续的,以2倍的方式进行扩容。vector<int> vec;//底层没有开辟任何空间通过push_back或者insert给vector添加元素的方法:0-1-2-4-8... 效率不高,在新的内存上用老内存的对象拷贝构造新对象,任何把老内存的对象析构,然后把老内存freereserve(20)和resize区别?在前面内容讲述过deque特点:动态开辟的二维数组空间,第二维是固定长度的数组空间;原创 2022-05-18 11:34:14 · 194 阅读 · 0 评论 -
236-C++STL(list)
listlist:链表容器底层数据结构: 双向的循环链表 pre data next1、增加元素list<int> mylist;增加:mylist.push_back(20); 从末尾添加元素 O(1)mylist.push_front(20); 从首部添加元素 O(1) //vec.insert(vec.begin(), 20) O(n)mylist.insert(it, 20); it指向的位置添加元素 O(1)//链表中进行insert的时候,先要进行一个query查询原创 2022-05-18 10:38:00 · 88 阅读 · 0 评论 -
235-C++STL(deque)
dequedeque: 双端队列容器底层数据结构: 动态开辟的二维数组,一维数组从2开始,以2倍的方式进行扩容,每次扩容后,原来第二维的数组,从新的第一维数组的下标oldsize/2开始存放,上下都预留相同的空行,方便支持deque的首尾元素添加。第一维空间大小是MAP_SIZE=2,第二维和元素类型有关。如果T是int类型,则第二维空间大小是4096/4=1024个。双端队列,两个端可以做队头,或者队尾。相当于2个方向都有2个角色。first和last处于中间的位置(512):为了让两原创 2022-05-18 10:28:42 · 179 阅读 · 0 评论 -
234-C++STL(vector)
1、vectorvector: 向量容器底层数据结构: 是动态开辟的数组,每次以原来空间大小的2倍进行扩容的1.1、添加操作vector<int> vec; 定义一个int类型的vectorvec.push_back(20); 在末尾添加元素 时间复杂度O(1) 有可能导致容器扩容vec.insert(it, 20); it迭代器指向的位置添加一个元素20 O(n) 有可能导致容器扩容插入1个元素,元素后边的所有元素都要向后挪动1个位置扩容示意图如下:以原来空间大小的2倍进原创 2022-05-18 09:55:45 · 588 阅读 · 0 评论 -
233-C++STL介绍
C++STL的介绍一、标准容器 C++11的array(数组容器) forward_list(单向链表容器)C++的 STL standard template libaray 都是标准模板库,Win和Linux可以直接使用!1、顺序容器 (底层是顺序表(数组,链表,栈,队列相关的))vector(向量容器)deque(双端队列容器)list(链表容器)2、容器适配器stack(栈)queue(队列)priority_queue(默认基于大根堆实现的优先级队列)3、关联容器无序关联容原创 2022-05-18 09:17:02 · 68 阅读 · 0 评论 -
231-C++语言级别提供的四种类型转换方式(const_cast & static_cast & reinterpret_cast & dynamic_cast)
C++语言级别提供的四种类型转换方式C语言中,类型强转一般就是这样:int a = (int)b;//把右边的类型强转成左边的类型,不安全,根据强转的类型造成内存大小会扩大的可能,访问不安全C++中:const_cast : 去掉(指针或者引用)常量属性的一个类型转换static_cast : 提供编译器认为安全的类型转换(没有任何联系的类型之间的转换就被否定了,就编译不通过)reinterpret_cast : 类似于C风格的强制类型转换,谈不上什么安全dynamic_cast : 主要用原创 2022-05-17 21:51:51 · 114 阅读 · 0 评论 -
230-分析并解决C++菱形继承问题
C++多重继承 - 菱形继承问题B和C的基类是A,B和C都从A单继承而来,D是从B和C多继承而来,D有2个基类:B和C我们把A称为D的间接的基类假设在A里面有ma这个成员变量很明显,我们可以看到问题,这里的派生类对象D有间接基类A多份的数据,这在我们的软件设计上肯定是有问题的;假设ma表示名字,我们不可能在派生类D上有2个名字,或者说ma代表身份id,在派生类D不可能有2个身份id,这是设计上的问题。不仅仅有菱形继承,还有这种继承:B从A单一继承而来,C有一个基类B,但是还同时从A原创 2022-05-17 19:22:58 · 233 阅读 · 0 评论 -
229-C++继承与多态(理解虚基类和虚继承)
多重继承好处是代码的复用,相当于一个派生类有多个基类。既从A继承又从B继承,C是从A,B多继承而来;C有2个基类:A和B;C可以把A和B的成员都继承而来,复用起来虚基类拥有纯虚函数的类称为 虚基类被虚继承的类称作虚基类,vbptr和vbtablevirtual的用法:1、修饰成员方法是虚函数2、可以修饰继承方式,是虚继承。被虚继承的类,称作虚基类A被B虚继承,所以A是虚基类我们打开命令提示符来看看A被B虚继承,所以A是虚基类A被虚继承,A本身内存布局没有变化我原创 2022-05-17 17:55:20 · 857 阅读 · 2 评论 -
225-C++继承多态笔试题实战
第1题#include <iostream>using namespace std;class Animal{public: Animal(string name) :_name(name) {} //纯虚函数 virtual void bark() = 0;protected: string _name;};//以下是动物实体类class Cat : public Animal{public: Cat(string name) :Animal(name) {}原创 2022-05-16 18:03:17 · 478 阅读 · 1 评论 -
224-C++继承与多态(抽象类)
抽象类抽象类和普通类有什么区别?抽象类一般不是用来抽象某一个实体类型,抽象类不能实例化对象,但是可以定义指针或者引用变量。普通类定义指针或者引用变量或者实例化对象都可以。一般把什么类设计成抽象类? 基类动物的基类本身就算是泛指,类->抽象一个实体的类型这里还用上一节的例子:定义Animal的初衷,并不是让Animal抽象某个实体的类型定义基类的好处:string _name; 让所有的动物实体类通过继承Animal直接复用该属性给所有的派生类保留统一的覆盖/重写接口原创 2022-05-16 15:44:25 · 292 阅读 · 0 评论 -
223-C++继承与多态(多态 & 继承的好处)
多态多态从字面上理解是:一个东西有多种多样的形态。1、静态(编译时期)的多态:函数重载 & 模板(函数模板和类模板)函数重载bool compare(int, int){}bool compare(double, double){} compare(10, 20); //call compare_int_int 在编译阶段就确定好调用的函数版本compare(10.5, 20.5); //call compare_douoble_double 在编译阶段就确定好调用的函数版本原创 2022-05-16 12:46:24 · 226 阅读 · 0 评论