C++篇
文章平均质量分 55
主要是发布关于C++的一些语法以及题
超超同学
个人比较热爱编程,平时也会分享一些经典题型,也希望大佬指出不足之处,之后改进
展开
-
c++前置前置声明(函数与类)
c++是以c的为基础进行后来改进的,而学过c语言的都知道,在c语言中,有时我们不可避免的要用声明,因为有时候我们在定义函数的时候,函数的定义写在了.cpp或是.c文件,而函数的声明我们一般放到了头文件中。很简单的一个原因,就是虽然我们使用了前置声明来告诉编译器存在A这个类,但是编译器此时并不知道的是A这个类的大小是多少,具体有哪些成员函数或者成员变量,所以我们在fun这个函数中使用A类实例化对象的时候,无法使用。声明是什么意思,就不多说了,很简单,也很好理解,但是声明也是有大坑的。我们先看看下面的代码。原创 2024-02-25 22:46:56 · 402 阅读 · 1 评论 -
C++make_pair,你真的懂了吗?
其次,这个代码压根就是错误的,都过不了编译,怎么跑,所以绕来绕去就又回来了,为啥错了,其实这里在vs上可以清楚的看到,虽然你显示的传了string&,但是编译器会给你加一个std::remove_reference_t这个类型,它的功能是去除引用,所以此时构建的pair类型是pair<string,string>的,所以导致编译出现报错,所以这理最好是使用pair,先不说不方便还是其他的,就光光是把make_pair显示的写出了模版类型,这就已经和pair差不多了,且make_pair还是错误的。原创 2024-01-17 21:29:00 · 618 阅读 · 0 评论 -
map,set的封装
首先就是,判断当前节点的右子树是不是空树,如果不是空树的话,那么代表的这个节点以及这个节点的做左子树已经访问完成,而右子树不为空,所还没有访问完这颗树,所以++之后就要找右子树的最左节点。相信大家都对map,set不会陌生,这是非常好用的容器,它的底层是红黑树,红黑树在数据结构中,个人感觉是比较难的一种数据结构,尤其是一会染色,一会旋转的,弄来弄去把人给弄晕了。这个思想还是有点绕人的,再就是其他的封装,如果看了我上一篇文章内容的伙伴,封装map,set应该还是很简单的。希望大家支持一下吧!原创 2023-10-14 20:34:08 · 156 阅读 · 2 评论 -
unordered_map与unordered_set的封装
这个重载函数的参数应该是K,但是你要插入的话,像unordered_map的插入是pair啊,所以,此时就必须要在unordered_map的这个文件中,调用Hash文件中的插入,在传下去。但是千万不要绝的实现unordered_map与unordered_set很简单,就像做饭一样,我们每个人都可以做出挂面,但是最后吃进嘴的感觉,味道是不一样,大厨做出来的大概率会比一个做饭小白做的好吃,而unordered_map与unordered_set就像做饭一样,想实现哈希捅不难,但是封装接口是真的难。原创 2023-10-14 13:52:10 · 125 阅读 · 4 评论 -
浅谈为什么多态只能是指针或引用
第二:因为在切片的时候,其实是发生了浅拷贝的,所以此时因该是A的对象与B的对象一样,不仅一样,如果他们中有指针,还是两个指针指向同一个地址的,但是这里明显没有,所以只有一个解释,那就是B在发生切片的时候,B的虚函数指针指向发生了变化。因为B继承了A,所以此时的B的虚函数指针指向的虚函数表与A不同,但是此时这里发生了切片,如果就像我们平时所说的,切片没有发生类型转换,只是将B类中A的那部分赋值给A的对象,那么此时按道理说赋值给A的对象的那个虚函数表,此时应该是B中重写之后的。但是不是,我们可以看看结果。原创 2023-09-24 19:50:21 · 216 阅读 · 2 评论 -
浅谈继承之默认成员函数
先说构造函数,其实不止构造函数,基类的默认成员函数,个人认为是不能被继承的(网上说法不一),因为继承之后,派生类就是一个整体,与基类没有任何关系,且派生类中不包含基类,所以他不可能继承构造函数,因为如果把基类的构造函数给继承下来了,那么,此时它只能构造基类的成员变量,那么派生类扩展的那些成员变量怎么办?相信学习过C++的哥们都知道的是,C++三座大山,分别是类与对象,继承,多态,也是面向对象的三大特性。所以,我个人认为是不可以继承的,想通这些,其实也就可以很好的理解隐藏,有各自的作用域这些知识了。原创 2023-09-23 17:53:12 · 83 阅读 · 2 评论 -
哈希表的实现(哈希捅)
如上,它的原理其实就是这样的,而哈希捅的实现其实使用链表来实现的,也就是每个桶都挂了一个单向链表,其实不仅可以挂单向链表,双向链表其实也可以挂,但是不用双向链表的原因是,双向链表比单链表的消耗大,所以才用的单链表,而在同一个桶的位置,挂数的时候,我们普遍用头插,这个就不说了,很容易理解,头插的时间复杂度是O(1)。上面就是我用哈希捅实现的哈希表,思维逻辑还是比较简单的,但是还是要注意的点。还有就是线性探测与二次探测的方法来实现哈希表,这个后面会陆续的发。本篇内容如果对你有用的话,希望带你一下赞吧!原创 2023-09-10 16:24:28 · 155 阅读 · 0 评论 -
手撕红黑树
其实AVL树和红黑树两个各有各的好处,是的,个人认为两个各有各的好处,因为AVL对树高比较严格,所以导致旋转点额次数就多,所以就会有额外的消耗,但是红黑树就没有这么多的消耗了,因为红黑树的上面几个规则,导致红黑树最长路径不得超过对短路径的两倍,所以,红黑树也会旋转,但是插入同等节点的条件下,红黑树旋转点次数肯定比AVL树少,但是AVL树是严格的logn,而红黑树是不太严格的logn,所以我说是各有各的好。如果不是,就把新插入的节点更新成祖父节点,依次往上更新,直到父节点为空或是父节点的颜色为黑色就停止。原创 2023-09-03 18:54:57 · 473 阅读 · 4 评论 -
手撕二叉平衡树
如上图,如果没有插入100,那么此时的二叉平衡树是平衡的,但是此时如果插入100,此时30这个节点的平衡因子是2,所以此时需要旋转来降低这棵树的高度,此时就是左旋。和左单旋一样,因为新插入的节点导致30这个节点的平衡因子为-2,所以此时就要旋转来降低这棵树的高度,此时是要右旋,这个和左旋一样,30是旋转点,25进行右旋,把25这个节点的右子树连接到30这个节点的左子树处就可以了。先把60当旋转点进行旋转,再把30当旋转点进行旋转,至于子树怎么连接,与先左旋,在右旋相同。2.链接parent指针。原创 2023-09-03 11:54:28 · 551 阅读 · 3 评论 -
STL之stack(适配器讲解以及双端队列的讲解)
所以在进行头插和头删,尾插尾删等时间复杂度是O(1)。它的底层是若干个数组组成的,然后头一个中控器,其中中控器中有遍历整个队列的迭代器,所以,我们可以知道的是,若是在中间插入删除,最好不要用双端队列,如果进行的操作是头插等,那么,此时可以用双端队列。我们可以这样理解,就是现实当中是的插排一样,上面有三个孔的,也有两个孔的,不管三个孔还是两个孔,只要我们插上对应的充电器,就可以给对应的电子产品充电。可以想一下,我们以前在学数据结构的时候,我们的stack有数组栈和链栈,所以,此时在理解,就比较好理解了。原创 2023-08-28 14:16:26 · 151 阅读 · 4 评论 -
STL之list模拟实现(反向迭代器讲解以及迭代器失效)
那就来说说实现方法吧。主要讲解的是,因为反向迭代器的实现底层是在正向迭代器的基础上实现的,所以反向迭代中的++对于正向迭代器来说,就是--,一定要区分开这个。首先是迭代器失效:list迭代器的失效与vector不同,list的迭代器在插入时不会有迭代器失效的现象,只有在删除的时候才有迭代器失效的现象,插入没有失效现象的原因,很简单,就不多说,而删除导致迭代器失效的原因是,在删除一个节点的时候,我们把这个节点所占的空间已经给释放了,所以此时指向这个节点的指针已经是野指针了,所以导致迭代器失效。原创 2023-08-25 21:07:52 · 905 阅读 · 2 评论 -
STL之vector(讲解迭代器失效,拷贝构造函数等现代版写法)
还有就是拷贝构造和赋值运算符的重载的现代版写法,其实个人建议的是,如果理解不了现代版的写法,可以按照深拷贝的思路来慢慢写,现代版的实现只不过是代码比较简洁而已,不过还是看个人喜好了,现代版的实现提高了成员函数的耦合性(个人认为不好的一点),如果出现错误的,维修成本比较大,而原始的写法就没有这种问题。我们可以看到的是,我在3这里插入了7,把所有的数后移了一位,但是,我们可以看到的是,此时原本3这个位置的数变成了7,但是迭代器的位置其实没有变,所以此时你如果不更新迭代器的话,就到导致迭代器的失效。原创 2023-08-24 19:57:13 · 284 阅读 · 3 评论 -
STL之string模拟实现
还有就是,大家一定要注意的是,在重载流插入和流提取的运算符时,个人认为插入既可以用友元函数,也可以自己写,上面有两种方法的代码,而在自己实现的过程中,一定要注意的是,cin其实是忽略空格和换行的,所以此时就要用到的是cin中的一个成员函数。而流提取不可以用友元函数,因为string中的打印是有多少打印多少,而不是遇见‘\0’就结束,这个一定要注意。首先就是,string是深拷贝,这个很简单,深浅拷贝在前面已经浅浅的说过一些了,深拷贝其实就是要让他们指向的空间不一样,这样析构的时候就没有错误了。原创 2023-08-24 12:58:28 · 136 阅读 · 2 评论 -
内存分布(以及new,delete)
内存分布讲解原创 2023-08-21 21:39:40 · 155 阅读 · 0 评论 -
C++语法总结
C++语法原创 2023-07-23 16:05:24 · 124 阅读 · 1 评论 -
C++浅谈const
所以正因为是传值返回,不管你在不在这个函数的前面加const,只要是你引用,你就得加const,因为它产生的临时变量是常性,但是我个人认为是直接不要引用传值返回的函数,以为在把这个返回值返回给你的时候,这里是会出问题的,因为list是刚好不需要在迭代器类中析构,所以可以正确,如果是其他的地方呢?然后返回主题,const到底加不加,加了的话,代表传值返回的是一个常量,然后会产生一个临时变量,临时变量具有常性,不加的返回的是一个变量,但是产生的临时变量依然具有常性,所以,我认为这里是加不加都可以,不影响。原创 2023-07-14 17:46:22 · 341 阅读 · 6 评论 -
C++类与对象赋值运算符的重载(运算符的重载)
特别要注意的是运算符重载的函数中,只有赋值运算符的重载是类的默认构造函数,所以,当你不写赋值运算符的重载的时候,编译器会默认生成一个赋值运算的重载,而这个赋值运算符的重载是浅拷贝(值拷贝)。类似于上面这样,自定义类型虽然不能随便赋值,但是内置类型可以啊,内置类型就是类中的成员变量啊,所以,可以把自定义类型的赋值理解为“大事化小,小事化了”这个思想,所以我们就可以把这个函数给重载一下,可以让他的成员变量分别赋值。所以,这里就出来了个赋值运算符的重载,就是相当于函数重载一样,把赋值这个符号给重载一遍。原创 2023-07-14 16:26:53 · 269 阅读 · 4 评论 -
C++类与对象(默认成员函数之拷贝构造函数)
上面的代码是我随便写的一个类,其实在这里析构函数是没有必要写的,不影响什么,原因在上一篇文章中说过,这里就不重复了,我们言归正传,来看看主函数中我实例化了两个对象,第一个也就是t,它很好理解,我传参传了10,没有用构造函数的缺省值,那么第二个对象他会怎么初始化呢?改了下代码,我们可以清楚的看到的是,d与t的地址是一样的,而我在拷贝构造函数中,参数设置的是const Time& d,所以大家不难想象,这个d就是t的别名,所以充分的证明了实例化s的时候,调用的是拷贝构造函数。用法前面的内容里有,而且非常详细。原创 2023-06-30 21:18:06 · 379 阅读 · 0 评论 -
C++类与对象(默认成员函数之析构函数)
我们前面知道的是,在实例化一个对象的时候,我们会调用一个构造函数,这个构造函数的作用是初始化我们类的成员变量,但是,有没有人想过,既然C++已经可以初始化成员变量了,那么,在我们程序即将结束的时候,是不是要把占用的内存归还给操作系统,但是你归还完以后,他这快内存可能还有一些数据是你没有清理干净的(尤其是一个函数中有在堆上开辟空间的,如果不释放这块空间就会导致内存泄漏),所以,此时的析构函数就是来清理这些数据的。我们可以看见他打印了出来,所以,我们就可以知道析构函数的作用是清理工作。而且他还不可以重载。原创 2023-06-18 14:48:57 · 99 阅读 · 2 评论 -
类与对象(this指针与默认成员函数之构造函数)
其实就是转换成了这个样子,注,这个样子编译是不能通过的,这个只是我们展开的样子,所以,我们平时写代码的时候的这个指针是被隐藏了的,所以这里我们要知道,还有要注意的一个点是,因为塔川的是对象的地址,所以this指针的地址是不能变的,所以,它的类型应该是*const,这个为什么我想大家应该都是知道的,C的内容我们就不在这复习了。所以这里就出现了一个this指针,它其实是隐藏起来的,当对象调用成员函数的时候,就会吧对象的地址传给他,这样理解的话,this指针其实本质是成员函数的一个形参,是个隐藏的参数。原创 2023-06-15 21:52:54 · 106 阅读 · 6 评论 -
C++类和对象
以上是它的三大权限和访问规则,这里不再多说,又不懂的小伙伴可以私聊。剩下的就是类的大小计算了,我们知道的是结构体有大小,也学结构体的大小是怎么算的,那么类的大小是怎么算的呢?其实也是很简单的,结构体中的内存对齐问题在类中还是继续用的,但是类的大小是不计算成员函数的大小的,所以,这样一来,类的大小计算方式和结构体的大小计算方式就是一样的了。好了,现在有了类,我们知道的是C++是面对对象的,C语言才是面向过程的,所以我们就算是实现了一个链表,也不可能让用的人知道里面到底是什么,所以这里就有了类的访问权限。原创 2023-06-06 20:07:27 · 56 阅读 · 4 评论 -
C++内联函数
我们明显看到,这里是没有展开的,这是为什么呢?其实这个是因为内联函数对于编译器来说只是一个建议,编译器可以选择不展开,因为展开之后,会使可执行程序变大,所以内联函数只有当指令行数比较小的时候才会展开。关键字是inline。注:递归函数是不会展开的,代码行数过大也是不会展开的,还有,内联函数最好是不要把声明和定义分开,这样子会有链接错误。首先,我们要知道的是,C++是补充了C的不足之处,所以C++是包容C的。而内联函数要想展开的话,它里面的代码行数是1-10行左右,但是我个人认为的是应该和他的汇编指令有关。原创 2023-05-29 15:12:02 · 59 阅读 · 4 评论