C++
文章平均质量分 83
分享C++的基础知识
多米诺骨牌㊫
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
C++静态成员函数
静态成员属于类但不属于对象,静态成员变量在类内声明类外定义,变量在类外分配空间。原创 2024-11-08 17:15:40 · 1033 阅读 · 0 评论 -
C++特殊类的设计
开头整体说明一下,要求特殊类不能实现的功能,一种方式是将这种方式私有化,另一种方式是用特殊的关键字控制。原创 2024-11-06 21:13:07 · 466 阅读 · 0 评论 -
优先级队列
首先要注意的就是别与队列(queue)搞混了,队列是一种先进先出(First in First out,FIFO)的数据类型。每次元素的入队都只能添加到队列尾部,出队时从队列头部开始出。优先级队列(priority_queue)其实,不满足先进先出的条件,更像是数据类型中的“堆”。优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义。比如定义元素越大优先级越高,那么每次出队,都是将当前队列中最大的那个元素出队。typename是数据的类型;原创 2024-11-04 22:36:09 · 959 阅读 · 0 评论 -
【C++11】异常处理
1.异常规格说明的目的是让函数使用者知道,可以在函数的后面接throw类(类型),列出这个函数可能抛出的所有异常。2.函数后面接throw(),表示函数不抛异常。3.若无异常接口声明,则此函数可以抛掷任何类型的异常。//只会抛A/B/C/D中的某中类型的异常//这里表示这个函数只会抛出bad_alloc这种异常这个函数不会抛异常在C++中,引入了noexception//表示如果x>y不发生异常,则Compare函数不会发生异常。原创 2024-09-22 19:55:54 · 1416 阅读 · 0 评论 -
C++回调函数
主要看最后一行,通过std::bind函数绑定了对象与对应的函数,这种方式比上面的通过类的成员函数进行回调更为简单方便。这个bind函数中的重载通常第一个是函数的指针,第二个是调用对象的指针,后面跟占位符。特别注意的是,因为函数名本身就可以表示该函数地址(指针),因此在获取函数指针时,可以直接使用函数名,也可以去函数的地址。前面函数指针的方式作为回调函数的一种方式,可以同时用于C和C++,下面介绍另外的一些方式,因为C++引入了对象的概念,可以使用类的成员和静态函数作为回调函数。下面看一个具体的例子。原创 2024-10-17 11:51:59 · 613 阅读 · 1 评论 -
哈希(无序容器,哈希表)
最好的查询时,进行很少次数的比较可以找到,因此在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树的结构的关联式容器使用的方式类似,只是其底层的结构不同,本文中只对unordered_map和unordered_set进行介绍,unordered_map和unordered_set可以查看文档介绍,与mutimap和mutiset是一样的。a是散列表装满程度的标志因子。插入的节点是一个pair类型,它的函数与map几乎是一模一样的,unordered的意思是混序的。原创 2024-10-02 22:56:25 · 1102 阅读 · 0 评论 -
C++IO流
ofs<<info._ip返回的是ostream&类型,而不是ifstream&类型,我们重载的是ifstream&类型,因此不能继续打印info._d。要想继续打印,需要将重载函数的ifstream&类型转换为ostream类型&。这也就是为什么cout可以同时处理多个对象的原因,例如:cout<<a<<b,cout<<a返回的是一个cout,然后再继续cout<<b。我们发现ifstream压根就没有对ostream中的<<的重载进行重写(没有必要),使用的依然是ostream这个类中的<<。原创 2024-09-27 19:50:20 · 1270 阅读 · 0 评论 -
【C++11新特性】多线程
主要通过RAII的方式,对其管理的互斥量进行了封装,在需要加锁的地方,只需要用上述介绍的任意互斥体实例化一个lock_guard,调用构造函数成功上锁,出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁,可以有效避免死锁的问题。在这段代码中,t1和t2两个线程对同一个信号量进行++操作,由于底层的++操作不是原子的,可能会导致x的数值混乱,因为对于一个++操作来说,它底层的汇编大概会分为三步,分别是ld,++,sd。但如果加在里面虽然是并行运行,这样频繁的加锁解锁是需要消耗资源的。原创 2024-09-24 10:54:18 · 1110 阅读 · 0 评论 -
【C++11新特性】类的新功能,可变模板参数,包装器
expand函数中的逗号表达式:(printarg(args), 0),也是按照这个执行顺序,先执行printarg(args),再得到逗号表达式的结果0。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包。看这样一段代码,有一个模板函数,当同时向它的F传入函数,仿函数,以及lambda表达式的时候会实例化三个模板。这就需要对参数包进行解析。原创 2024-09-19 21:25:43 · 851 阅读 · 0 评论 -
【C++11】统一列表初始化,声明,新增容器,lambda表达式
C++11更像是一种从C++98/03中孕育出来的一种新的语言,C++11能更好的用于系统开发和库开发,语法更加泛化和简单化,更稳定安全,不仅功能强大,而且能提高程序员的开发效率。int _x;int _y;printf("调用了构造函数\n");//当没有构造函数时会兼容C语言的特性,当有构造函数时会调用构造函数。原创 2024-09-19 15:55:20 · 952 阅读 · 0 评论 -
【C++11】右值引用,完美转发
默认生成的移动赋值重载函数,对内置类型直接进行赋值,对自定义类型,如果由对应的移动赋值重载函数就调用其对应的移动赋值重载函数,如果没有则直接调用拷贝赋值。默认生成的移动构造函数,对内置类型进行值拷贝,对自定义类型,如果由对应的移动构造函数就调用其对应的移动构造函数,如果没有那么调用拷贝构造。通过观察打印结果可以发现,显然移动构造没有再开辟空间,而是直接将数据进行转移,节省了空间,由临时变量进行拷贝构造给ret还会创建一个新的对象,消耗空间。左值引用不能给右值取别名,右值引用也不能给左值取别名。原创 2024-09-18 22:25:21 · 909 阅读 · 0 评论 -
命名空间和函数重载
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}。int val;原创 2024-04-23 19:53:02 · 264 阅读 · 0 评论 -
类和对象C++
class为定义类的关键字,Classname为类的名字,{}中为类的主体,注意类定义结束时后面的分号不能省略。类体中内容称为类的成员:类中变量称为类的属性或成员变量‘类中的函数称为类的方法或者成员函数。// 类体:由成员函数和成员变量组成// 一定要注意后面的分号1.声明和定义全部放在类体中,需要注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。2.声明在.h文件中,类的定义放在.cpp文件中。原创 2024-05-08 15:13:16 · 1154 阅读 · 0 评论 -
赋值运算符重载
我们直接将这个运算符重载函数写到类里面报错显示operator的参数太多,因为operator>作为成员函数的第一个参数默认会传给this指针。原创 2024-05-09 15:42:48 · 1173 阅读 · 0 评论 -
C++类和对象(下)
将const修饰的"成员函数"称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象来访问外部类的所有成员。但外部类不是内部类的友元类。友元类,实际上就是把这个类定义为另一个类的友元类(即A类是B类的友元,A可以访问B中的私有成员变量以及保护成员变量)(4)内部类就是外部类的友元类(内部类:如果一个类定义在另一个类的内部,这个内部类就叫做内部类)原创 2024-05-15 10:45:51 · 675 阅读 · 0 评论 -
累加求和用内部类的方法
(1)构造函数:对自定义类型调用它的默认构造,new开辟了几个空间就会调用几次默认构造。(3)内部类是外部类的友元类,可以随意调用外部类的私有变量。(2)静态变量在静态区,所有函数共用一个静态变量。求:1+2+3+...+n。利用了C++的几个性质。原创 2024-05-19 22:04:52 · 207 阅读 · 0 评论 -
内存管理之new和malloc
new会调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。特性分析使用char*p=new char[100]申请一段内存,然后使用delete p释放,有什么问题?原创 2024-05-22 15:29:44 · 620 阅读 · 0 评论 -
C++流插入和流提取重载
但ostream是库的,不能随便修改。原创 2024-05-31 20:31:21 · 398 阅读 · 0 评论 -
(C++)string模拟实现
为防止new失败,所以使用临时变量tmp指向new出来的空间,若new成功,释放旧空间,并将—_str指向新的空间。通过reserve类似扩容的操作,扩大了字符串长度的空间,并且在原字符串‘\0’的位置上拷贝str字符串。const只能调用const,非const既可以调用非const,也可以调用const。注意:将char*传给const char*是范围缩小,因此只能1:1构造一个。内置类型,调用默认成员函数,自定义类型调用默认构造。浅拷贝(值拷贝):拷贝一个指针,指向同一片空间。原创 2024-06-10 11:20:49 · 485 阅读 · 0 评论 -
vector迭代器失效
当删除元素后,pos位置之后的元素会往前搬移,没有导致底层空间改变。原因:迭代器指向初始空间的首元素,尾插元素时空间不足,开辟更大的新空间存储元素,释放旧空间,但此时it仍旧指向已经释放的旧空间,成为了野指针。后面对野指针解引用就会导致程序崩溃。但是,如果pos元素刚好是最后一个元素,删完后pos就刚好是end()的位置,而end()位置并没有元素,那么一旦试图解引用迫使就会崩溃,类似数组访问越界。解决办法简单粗暴:在所有可能导致迭代器哦失效的操作之后,如果要使用迭代器,在使用前重新赋值,使其指向新空间。原创 2024-06-13 22:09:58 · 444 阅读 · 0 评论 -
vector模拟实现
2)扩容时为什么不适用memcpy,因为假如vector的每个成员是string类型或者vector类型,memcpy按字节拷贝只会将三个指针拷贝过去,属于浅拷贝,没有开辟新的空间。进入范围for后需要调用begin()函数,但是v是const类型,无法调用非const类型函数,因此需要一个this指针是const类型的begin()函数。用一段迭代器区间进行初始化,由于不同类型的容器迭代器类型可能不同,因此设计成函数模板,将区间内的内容尾插到vector即可。当n大于capacity时,扩容之后在赋值。原创 2024-06-18 11:06:02 · 289 阅读 · 0 评论 -
迭代器和指针的区别以及const修饰指针
1)迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,通过重载了指针的一些操作符,->,*,++,--等封装了指针,是一个“可遍历STL(Standard Template Library)容器内部或部分元素”的对象,本质是封装了原生指针,是指针概念的一种提升,提供了比指针更高级的行为,相当于一种只能指针,它可以根据不同类型的数据结构来实现不同的++,--等操作;总之,指针和迭代器是有很大差别的,虽然他们表现的行为相似,但是本质是不一样的!*放在const前面修饰的是指针,即(p)原创 2024-06-21 17:00:37 · 413 阅读 · 0 评论 -
list的模拟实现
首先,C++中用struct定义是可不加struct,重点是这里用了一个类模板,类模板的类名不是真正的类型且类模板不支持自动推类型,即_list_node不是真正的类型,定义变量时,_list_node这种才是真正的类型,也就是用类模板定义变量时必须指定对应的类型。注:结构体模板或类模板在定义时可不加,但使用时必须加。原创 2024-07-11 14:03:18 · 830 阅读 · 0 评论 -
C++:继承
定义:继承机制是面向对象程序设计中使用代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生的新类,称为派生类(或子类),被继承的类称为基类(或父类)。继承呈现了面向对象程序设计的层析结构,体现了由简单到复杂的认知过程。之前接触的复用都是函数复用,继承是类设计层次的复用。//定义了一个父类public:string name = "小明";//定义了一个以public方式继承父类的子类studentpublic:int main()原创 2024-07-18 10:08:03 · 962 阅读 · 0 评论 -
C++ 多继承
而内存2也有一个专有名词:虚基表、通过观察内存中的布局,我们发现d中的B父类对象和C父类中的内容分别是连续存放的,B中有父类A中成员_a的值是1,其自己成员_b的值是3,两者的内存是挨着的,C同理,对于D类中自己的成员_d,放在了内存的最后。这里00 00 00 00的意义在多态中会学到,注意看他的下一个位置存放的是00 00 00 14,这里是十六进制,因此表示的是20这个数字。总结:A一般叫做虚基类,在D里面,A类成员放在放在一个公共的位置,有时B要找A,C要找A,就要通过虚基表中的偏移量进行计算。原创 2024-07-20 17:56:50 · 1296 阅读 · 0 评论 -
C++多态的用法详解
我们反观上述中动态多态的定义,用父类的引用或者指针(这里使用的是Person& p)来接收不同类型的对象(p1和p2),该引用或指针调用相同的函数(都调用了p.BuyTicket()),都调用了各自类中不同的函数(打印的结果不同)。虚函数的重写又称为虚函数的覆盖(重写是表面意义上的,覆盖是指原理上的):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型,函数名,参数列表完全相同),称子类的虚函数重写了父类的虚函数。我们称派生类的虚函数为基类的虚函数的协变。原创 2024-07-22 14:31:33 · 855 阅读 · 0 评论 -
C++多态的底层原理
实际中我们不建议设定出菱形继承或者菱形虚拟继承,在实际中很少使用。原创 2024-07-26 21:44:39 · 847 阅读 · 0 评论 -
C++搜索二叉树和Key/value模型的应用
每一次出现一个元素我们就将它插入二叉搜索树中,并把它的value赋值为1,当第二次遇到这个元素的时候,在二叉搜索树中搜索该元素,人如果可以找到该元素则将该元素的value的值++。比较parent的_k与k的大小,判断cur建立在parent的左子树还是右子树。2.如果cur的左为空,判断cur相对于parent的位置,并将cur的右子树赋值到cur相对于parent的位置处,并删除cur。2.比较cur->_k与要查找的节点k的值的大小关系,当_k原创 2024-08-01 23:07:56 · 969 阅读 · 0 评论 -
手撕AVL树
在AVL树中,除了需要定义平衡因子bf之外,还需要定义指向节点父节点的指针。方便我们来进行平衡因子的更新。int _bf;,_kv(kv),_bf(0){}同时和map一样,我们使用pair类型来进行数据的存储。原创 2024-08-13 20:47:46 · 756 阅读 · 0 评论 -
STL详解---set和map
注意set只有增删查,没有修改的函数。这是因为一旦修改了key的值,set就不是一棵搜索二叉树了。set底层的普通迭代器的实现和const迭代器的实现是一样的。*pos是一个常量。此时会发生报错。原创 2024-08-14 14:41:05 · 778 阅读 · 0 评论 -
C++手撕红黑树
红黑树的表意就是一颗每个节点带有颜色的二叉搜索树,并通过对节点颜色的控制,使该二叉搜索树达到尽量平衡的状态。红黑树确保没有一条路径比其他路径长两倍。和AVL树不同的是,AVL树是一棵平衡树,而红黑树可能平衡也可能不平衡(因为是尽量平衡的状态)每一次插入都对根节点置为黑操作,因为第一种情况可能导致根节点不是黑。同时对根节点置黑也并不违反三条规定。原创 2024-08-15 11:34:12 · 789 阅读 · 0 评论
分享