C++
指针和引用的区别
-
指针是一个变量,存储的是内存中的一个地址,引用只是一个别名,和原来变量是同一个东西
-
指针可以有多级,引用只能有一级,不存在多级引用
-
指针在初始化是可以为空,在定义时可以不进行初始化(但是不建议,使用未初始化的指针可能会造成野指针的情况),但是引用必须要进行初始化且引用不能为空
-
sizeof(指针)得到是指针的大小(32位机大小为4, 64位机大小为8),sizeof(引用)得到的指向的变量的大小
-
引用一旦经过初始化后就不能被改变,指针经过初始化后还能够重新改变指向
指针常量和常量指针的区别
- 指针常量:指针常量是对指针做限制,因此我们不能修改他的指向,但可以修改它所指向的内容,简而言之就是地址不能改变,内容可以改变
- 常量指针:常量指针是对常量做限制,因为我们不能修改它的内容,但能够修改他的指向
sizeof() 和 strlen()的区别
- sizeof是关键字不是函数是关键字不是函数是关键字不是函数,strlen是字符处理函数
- sizeof参数可以为任何数据的类型或者数据,strlen的参数只能是字符指针,且计算大小时到‘\0’结尾
const关键字
-
const常量必须要在定义时进行初始化,之后无法更改
-
const形参可以接受const参数和非const参数
-
const对象只能调用const成员函数,非const成员既可以调用const成员函数,也可以调用非const成员函数
static关键字
- 隐藏 所有不加static的全局变量和函数都具有全局可见性,可以在其他文件中使用,加了之后对于其他文件不可见
- static变量默认初始化为0,存储在静态区
- static成员变量只与类关联,不与对象关联,每个类只有一个,需在类中定义,在类外初始化
- static成员函数不具有this指针,由于没有this指针,所以无法调用非static成员函数和非static成员变量
C++中struct和class的区别
- 相同点
- 两者都可以添加成员变量和成员函数,权限都有共有和私有部分
- 在C++中struct和class没有区别
- 不同点
- struct默认public,class默认private
- class默认private继承,struct默认public继承
tip:
- 在c语言中,struct是用户自定义数据类型,里面不可以添加成员函数,在C++中可以添加成员函数
new/malloc和deete/free的区别
-
这两组操作都是用于动态内存的申请和释放
-
new和delete都只是关键字,malloc和free都是函数
-
malloc/free是标准库函数,new/delete都是运算符,可以进行重载
-
malloc函数原型
void* malloc (size_t size);
返回值为void*
在使用中必须要进行强制转换,new和deletet返回的是具体类型指向的指针 -
malloc需要手动计算所需要分配的空间大小,单位为字节,而new是自动进行推导
-
在底层实现中,new调用名为
operator new
的标准库函数分配足够的空间并调用相关对象的构造函数,malloc只是单纯的从堆上申请空间,同理,delete也是对指针指向的对象运行适当的析构函数,然后通过调用名为operator delete
的标准库函数释放该对象指向的内存
宏定义和typedef区别
- 宏定义主要是用于定义常量或者对简单的函数进行封装,typedef主要用于定义类型别名
- 宏替换发生在预处理阶段,只是简单的进行替换,不会进行安全检查,typedef在编译期工作,会进行安全检查
- 宏定义不是语句,不需要在句末添加分号,typedef是语句,需要加分号作为句末标识
野指针和悬空指针
- 这两种指针都是要求我们在使用中要注意和避免的,都是指向了五无效内存,直接机型访问的话可能会出现不可预估的后果
- 野指针—是指没有经过初始化的指针,因此我们在申明指针时应该将其置为空
- 悬空指针—指针指向的内存已经被释放,使用指针有可能会出现不可预料的后果,为了避免这中情况,当我们释放指针指向的内存后,一定要将指针置空
堆和栈的区别
- 申请方式不同
- 栈由系统自动分配
- 堆是由程序员自己进行申请和释放的
- 申请大小限制不同
- 两者生长方向不同,堆是向上生长,栈是向下生长
- 栈顶和栈底在内存中大小是设置好的
- 申请效率不同
- 栈由系统进行分配,速度快,不会出现碎片
- 堆由程序员进行分配,速度慢,效率低,且会出现碎片
C++和C语言的区别
- C++中new和delete是对内存分配的运算符,取代了C中的malloc和free
- 标准C++中的字符串取代了标准C函数中的字符数组
- C++使用iostream类库代替了C中的stdio函数库
- 在C++中,允许函数具有相同的名称,也就是重载,但在C语言中,重载是不被允许的
- C++语言中,允许变量定义在语句中的任意地方,只要是在使用前就可以,在C语言中,必须要在函数的开头部分进行定义,且不允许重复定义变量
- C++新增了关键字
哪些情况必须要使用初始化列表对成员进行初始化
- 初始化一个const成员
- 初始化一个reference成员
- 调用一个基类的构造函数,而该函数有一组参数
- 调用一个数据成员对象的构造函数,而该函数由一组参数
数组名和指针的区别
- 二者均可以通过增减偏移量来访问数组中的数据,例如a[1] , *(p+1)
- 当数组名被当作形参传递给函数时,就会退化成为一般指针
define宏定义和const的区别
- define是在编译的预处理阶段起作用,对变量进行替换,而const是在编译阶段才会起作用
- define只会进行替换,不做类型检查和计算,容易产生错误且不易发现
- const常量具有数据类型,编译器可以对其进行安全类型检查
计算类的大小
- 非静态成员的数据类型大小之和
- 编译器加入的额外成员变量(虚表指针)
- 为了内存对齐而进行的处理
- 如果一个类为空类,那么该类的大小为1,是为了在内存中进行占位
变量的声明和定义的区别
- 声明仅仅是把变量的声明的位置及类型提供给编译器,并不分配内存空间;定义要在定义的地方为其分配存储空间
- 一句话总结就是变量的声明只会告诉编译器有这个东西而不会为其分配内存,变量的定义会为变量分配内存
strcpy和memcpy的区别
- 复制的内容不同 strcpy只能够复制字符串,而memcpy可以复制任意内容,例如字符数组,整型,结构体,类等
- 复制的方法不同,strcpy不需要指定长度,它遇到被复制字符串的结尾符
\0
才结束,所以strcpy可能会导致溢出,并不安全,建议在使用中使用strncpy,memcpy则是根据其第三个参数决定复制的长度 - 用途不同,通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
final和override关键字
override
- 当在父类中使用了虚函数之后,我们有可能会在子类中对这个虚函数进行重写,如果我们没有使用override关键字,我们对基类虚函数foo()进行重写时可能会写成f00(),编译器就会认为我们并没有对虚函数进行重写,而仅仅只是添加新的成员函数,因此,override的作用就是强制认为子类中的这个函数是对基类的重写,如果基类中没有这个函数,则会报错。
final
- 当我们不希望某个类被继承,或者不希望某个虚函数被重写,我们认为这个类或者这个虚函数就是最后一个了,我们就可以在类名和虚函数后面添加关键字final,以达到这样的效果
什么时候调用拷贝构造函数,什么时候调用赋值构造函数
- 构造函数是函数,赋值运算符是运算符重载
- 拷贝构造函数是生成了新的类对象,赋值运算符只是对已有对象进行重新赋值
- 拷贝构造函数是直接构造一个新的类对象,所以初始化对象前不需要检查源对象和新建对象是否相同,赋值运算符需要先检查当前当前对象和被赋值对象是否相同,如果相同,则直接返回,如果不同,则需要先释放原有内存,然后再进行赋值
- 形参传递是调用拷贝构造函数,但并不是所有出现=的位置,都是采用赋值运算符,判断依据参照第二点
C++三大特性
- 封装 封装就是把客观的事物封装成抽象的类,数据和代码被捆绑在一起,避免外界干扰和不确定性访问,只让对象访问可以访问的,而对于不想让对象访问的进行隐藏,例如一个人有眼耳鼻舌口,四肢五官,这都是人的属性,除此之外,作为人还有衣食住行这些方法,那么我们就可以将这些属性和方法进行封装,封装成一个人类
- 继承 可以让某种类型对象获得另一个类型对象的属性和方法,每个人都有不同的职业,例如老师,学生,警察,他们都具有人的基本属性和方法,除此之外,老师需要备课,学生需要完成作业,警察需要维护治安安全,他们都可以继承人类然后添加自己独有的方法和属性
- 多态 不同对象收到同一消息做出不同的响应, (重载时实现静态多态,虚函数实现运行时多态),举例来说就是当我们的老师和学生都听到上课铃声时,老师会走向对应教师开始上课,学生听到上课铃声则要坐在教室里认真听讲
什么是内存泄漏
- 内存泄漏是指由于程序员的疏忽或错误造成了程序未能释放掉不再使用的内存,内存泄漏 并非指内存在物理上消失,而是说我们失去了对这段内存的控制
C++内存分区模型
- 栈 就是由编译器需要的时候进行分配,申请和释放都不需要程序员参与的存储区,效率很高,但空间有限
- 堆 就是我们使用
new
进行申请的内存块,要记住,一个new就要对应一个delete,如果程序员不进行释放,那么在程序结束后,操作系统会这些空间进行回收 - 全局数据区 就是我们用来存储全局变量和静态变量的地方,该处变量若在程序中未经初始化,则会被初始化为0
- 常量存储区 该处存放的都是常量,用户只能够进行读不能够进行写
- 代码区 存放函数体的二进制代码