C++基础知识

malloc 指针使用前要先判空,不然 C6011:取消对NULL指针的引用
OO(Object oriented)面向对象,包括有OOA面向对象的分析,OOD面向对象的设计,OOP面向对象的实现
C++编译器在2022年的今天已经被三个编译器占据了大部分的市场,那就是GCC、Clang、MSVC 。

python和c++,布尔和浮点可以相加或相乘
python不能字符和整形相加,c++可以

C++相关

  • C/C++需要通过编译器,把源代码编译成中间文件(.o和.obj),然后通过连接器和汇编器生成机器码,可以直接让计算机执行。这些机器码也就是我们通常的exe文件。

  • 当在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,应该在调用函数的文件顶部声明函数。

  • static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。

  • 调用函数时,有三种向函数传递参数的方式:
    C++基础知识_第1张图片

  • c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.,这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。

  • 为了避免同一个文件被include多次
    1 #ifndef方式
    2 #pragma once方式

  • 回调函数:指 使用者自己定义一个函数,实现这个函数的程序内容,然后把这个函数(入口地址)作为参数传入别人的函数中,由别人的函数在运行时来调用的函数。简单来说,就是由别人的函数运行期间来回调你实现的函数。

  • 许多c/c++的项目会使用cuda加速其算法,c/c++有其编译器:gcc/g++,cuda有其编译器nvcc。为了实现我们的目的,我们一般采用gcc/g++编译c/c++部分代码,nvcc编译cuda代码部分,即分离式编译。

C++进阶

C++基础知识_第2张图片

C++类

公有继承: 当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
私有继承: 当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
函数重载: 同一个类中相同的方法名。而多态是针对继承情况,基类派生类中相同的方法名
虚函数: 派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。希望在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
纯虚函数: 在派生类中必须重写
抽象类: 类中至少有一个函数被声明为纯虚函数
C++基础知识_第3张图片

Const和Static

Static与Const的区别

STL标准模板库

C++中STL用法超详细总结
STL(Standard Template Library)即标准模板库,特点是数据结构和算法的分离;不是面向对象的。

  • STL中六大组件:
    容器(Container),是一种数据结构
    迭代器(Iterator),提供了访问容器中对象的方法。
    算法(Algorithm),是用来操作容器中的数据的模板函数。
    仿函数(Functor),和容器类似,不支持迭代器
    适配器(Adaptor)
    分配器(allocator)

  • 两类七种容器
    序列容器(Sequence containers),每个元素都有固定位置取决于插入时机,vector(动态数组)、deque(双向队列)、list(双向链表)
    C++基础知识_第4张图片
    关联容器(Associated containers),元素位置取决于特定的排序准则,和插入顺序无关,set(相同数值的元素只能出现一次)、multiset(包含多个数值相同的元素)、map(同数值的元素只能出现一次)、multimap(可包含多个数值相同的元素)

动态库、静态库

VS下动态库dll的显式调用(动态调用)
调用DLL文件的两种方法(显式调用/隐式调用)
静态调用(隐式调用)和动态调用(显式调用)区别
1、静态调用时,如果exe所在的文件夹没有dll文件及其lib文件,则运行exe会报错。及exe根本就运行不起来 ,系统提示没有找到dll文件等信息。错误信息是不可控的。
2、动态调用只有再调用dll文件时,如果没有,才会报错,并且此错误时可控的。如果dll没有对应的.lib文件,那么就只能使用动态加载的方式了。

C++基础知识_第5张图片

指针

  • 指针与数组:
  • 指针与函数:
  • 指针与结构体:

句柄与指针的区别

你朋友给你写信,他直接写你名字邮局是找不到你的,他就写出你家的门牌号,邮局通过门牌就能找到你了,那么门牌就是指针,而你本身就是指针指向的内存值.

你由于去砸110车窗户被关进局子(打比方呵呵,别打我~),和你一起的有老外,有外星人,大家名字都很长,很难记,监狱长为了方便,给每个犯人一个标号,比如你是0001,而另一个火星人是0002,那么以后监狱长碰到0001就知道是你了,不会去找火星人麻烦的.那么这个编号就是句柄,而你就是0001所代表的资源.

指针是指向,句柄是代表,2个有很大的区别.代表的话,我用0001是代表,用abcdef还是代表,而门牌,就要按照规矩来,你不能用0003来代表XX街XX号的门牌

头文件

在C/C++中,头文件(.h)一般用来声明函数或类,然后在实现文件(.cpp)中实现。声明是为了让编译器知道函数和类的存在形式,因此一定要出现在实现或者使用的地方前面。声明可以重复,而实现只能有一次。头文件的意义可以形象的描述为:
1.我给别人提供哪些接口(导出第三方库供别人使用时,要通过头文件来描述库所提供的接口有哪些);
2.我要用别人哪些接口(通过包含第三方库的头文件,可以使用库中所提供的接口);
3.我要实现哪些接口(头文件中的声明,要在一个或多个包含该头文件的实现文件中实现)。

头文件几个好处:
1,头文件可以定义所用的函数列表,方便查阅你可以调用的函数;
2,头文件可以定义很多宏定义,就是一些全局静态变量的定义,在这样的情况下,只要修改头文件的内容,程序就可以做相应的修改,不用亲自跑到繁琐的代码内去搜索。
3,头文件只是声明,不占内存空间,

C++头文件的作用以及用法

chrono头文件是C++中用于解决关于时间问题的头文件
io.h主要定义一些和缓冲区相关的读写函数
cstdio.h是将stdio.h的内容用c++头文件的形式表示出来。stdio.h是c标准函数库中的头文件。
includeC标准库里面的函数库,需要手动添加命名空间。
includeC++标准库的函数库,默认自动添加命名空间。

  • IO库
    iostream(用于读写流的基本类型)
    fstream(读写文件的类型)
    sstream(读写内存string对象的类型)

堆和栈的区别

基础知识篇——堆内存和栈内存

  • 堆空间由程序员分配释放,栈空间由操作系统(编译器)自动分配释放。栈使用一级缓存,堆使用二级缓存。如果未能对堆内存进行正确的释放,会造成内存泄漏,但在程序结束时,会由操作系统自动回收。

  • 堆是不连续的区域,所以空间比较大,而栈是连续的存储区域,所以空间比较小

  • 碎片问题:对于堆,频繁的new/delete会造成大量内存碎片,降低程序效率。对于栈,它是一个先进后出(first-in-last-out)的结构,进出一一对应,不会产生碎片。

  • 局部变量都在栈中,不管是字符串还是数组还是指针

堆内存是一种按需分配的动态内存管理机制,这种机制能让数据在内存里存活时间超过定义它的函数的生命周期(不去销毁就一直在那儿),也能让多个线程共享同一个内存里的结构体/对象(任何线程只要拿到这片内存的地址和大小就能访问)。但是由于它的动态,你不能仅靠一个变量名就知道每一份数据在内存里的确切位置,导致要访问它里面的数据必须通过指针或引用

1、谁分配;2、分配在哪;3、分配的什么。

栈内存:存储的都是局部变量,凡是定义在方法中的都是局部变量(方法外的是全局变量),for循环内部定义的也是局部变量,是先加载函数才能进行局部变量的定义,所以方法先进栈,然后再定义变量,变量有自己的作用域,一旦离开作用域,变量就会被释放。栈内存的更新速度很快,因为局部变量的生命周期都很短。

堆内存:存储的是数组和对象(其实数组就是对象),凡是new建立的都是在堆中,堆中存放的都是实体(对象),实体用于封装数据,而且是封装多个(实体的多个属性),如果一个数据消失,这个实体也没有消失,还可以用,所以堆是不会随时释放的,但是栈不一样,栈里存放的都是单个变量,变量被释放了,那就没有了。堆里的实体虽然不会被释放,但是会被当成垃圾。

extern “C” _declspec (dllexport)用法

extern “C” _declspec (dllexport)目的是为了使用DllImport调用C++的DLL文件。因为使用DllImport只能调用由C语言函数做的DLL。
extern "C"外部声明,表示函数和变量是按照C语言的方式编译和链接的。
__decspec(dllexport)目的是为了将对应的函数放入到DLL动态库中。

extern "C "只是表示这个可以被C语言调用,除了这个之外,没有什么更多含义。
因为C语言的编译器和C++的不同,C++的会有个叫做函数名打散的机制,比如函数:int add(int a,int b)在C++里面编译之后,就不是int add(int a,int b),而是类似:int add@WEROIUERH(int a,int b)的函数名,而且是随机的,如果不用extern "C ",C语言根本没法调用,而在C++里面可以通过@的顺序来调用。
__declspec (dllexport)输出函数的时候,用loadlibrary又有何不可?
关键是你要知道输出符号的名字。
因为c++中有函数重载,通过函数名并不能唯一确定一个函数,所以使用c++方式编译函数时系统会在目标码中的内部修饰符中加入参数信息和返回值信息等, 这时候你能估算出正确的名称吗?
如果加了extern "C "则是用c的方式编译,函数在目标码中的内部修饰符就是_函数名,只要用函数名就可以调用
由于C++里面有函数重载,所以在编译的时候,编译器会在你写的,也就是你希望导出的函数
后面加上一些关于参数的信息,也就是真正导出的函数名字和你想要的不一样。
又由于C语言没有函数重载,所以用EXTERN "C"的意思就是告诉编译器不要按照C++那样修改函数
名称。

dumpbin

如果查看a.dll库中包含哪些函数,可以使用:dumpbin /exports a.dll >1.txt
如果查看b.exe中加载了哪些动态库,可以使用:dumpbin /imports b.exe >2.txt
如果查看c.lib中包含哪些函数,可以使用:dumpbin /all /rawdata:none c.lib >3.txt
如果查看d.obj中包含哪些函数,可以使用:dumpbin /all /rawdata:none d.obj >4.txt

位于C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64

图像存储C++基础知识_第6张图片C++基础知识_第7张图片

内存泄漏

什么是内存泄漏,常见引起引起内存泄漏的原因,及解决办法
C++中内存泄漏的几种情况
一个线程的栈内存是有限的。栈上的内存通常是由编译器来自动管理的。当栈上分配一个新的变量时,或进入一个函数时,栈的指针会下移,相当于在栈上分配了一块内存。我们将一个变量分配在栈上,也就是利用栈上的内存空间,当这个变量的生命周期结束时,栈的指针会上移,相当于回收了内存。由于栈上的内存的分配和回收都是由编译器控制的,所以在栈上是不会发生内存泄漏的,只会发生栈溢出(Stack Overflow),也就是分配的空间超过了规定的栈大小。

而堆上的内存是由程序直接控制的,程序可以通过 malloc/free 或者 new/delete 来分配和回收内存,如果程序通过malloc/new 分配了一块内存,但忘记使用 free/delete 来回收内存,就会发生内存泄露。

你可能感兴趣的:(c++)