什么是虚函数?什么是纯虚函数?
虚函数是在基类中用virtual声明的成员函数,应许在派生类中重写该函数,虚函数主要实现多态性。
虚函数的特点是在动态绑定时,虚函数的调用在运行时决定,而不是编译时,通过基类指针或引用调用虚函数时,实际调用的是派生类的重写。
虚函数通常通过基类的指针或引用来调用,实现对不同派生类实例化对象的统一操作。
虚函数可以在基类中实现也可以在派生类中重写。
纯虚函数是在基类中为虚函数但没有实现的函数,使用=0来表示,纯函数使得基类成为抽象类,不能实例化对象。
纯虚函数的特点是属于抽象类,不能创建该类的实例化对象,抽象类的目的是提供一个接口供派生类实现;派生类必须重新所有纯虚函数才能被实例化,如果派生类没有实现所有的纯虚函数,它也会成为抽象类;纯虚函数常用于定义接口,确保派生类提供特定的功能实现。
基类为什么需要虚析构函数?
为了解决在使用delete释放基类指针时,由于基类的指针的作用域仅仅是基类空间的内容,可以完成对基类空间的释放,派生类的空间无法释放,导致内存泄漏的问题,当基类的析构函数设置成虚析构函数时,能够指引delete关键字在释放基类指针时,连同派生类的空间异同释放、
如果初始化const和static数据成员
const数据成员必须在构造函数的初始化列表中进行初始化,因为它们不能再构造函数体内被赋值
static数据成员属于类本身而不是类的某个对象的变量,必须在类外进行初始化,不能在类定义中直接初始化。
指针和引用的区别
有一些几点区别
- 在定义时
指针是一个变量,它存储另一个变量的内存地址。指针可以指向任何类型的数据,包括基本数据类型、对象、数组等。
引用:引用是一个别名,它是一个已存在变量的别名。引用必须在声明时初始化,并且一旦绑定到一个变量,就不能再绑定到其他变量。
- 初始化
指针:可以在声明时不初始化,之后可以指向任何变量或设置为空
引用:必须在声明时初始化,并且不能在后续代码中更改引用的对象
- 重新绑定
指针:可以在任何时候重新指向另一个变量。
引用:一旦绑定到一个变量,就不能再绑定到其他变量。
- 内存管理
指针:指针可以动态分配内存,并且需要手动释放内存。
引用:引用不需要手动管理内存,因为它们只是变量的别名,不涉及内存分配
- 空值
指针:可以指向空,表示不指向任何有效的内存地址
引用:不能为引用赋值为 空,引用必须始终引用一个有效的对象
总结:指针:可以指向任何类型的变量,支持动态内存管理,可以重新绑定,允许空值,使用时需要解引用。
引用:是变量的别名,必须在声明时初始化,不能重新绑定,不能为空,使用时更为简洁
New和malloc的区别
1: malloc\free是标准库中提供的函数,属于函数调用,而new\delete是C++中的关键字,无需开辟函数内存空间
2:malloc\free申请空间时,没有单个和连续空间的区别,而new\delete申请时区分单个和连续空间的操作
3:malloc\free申请空间时,需要手动计算要申请空间的大小,而new\delete申请空间时,会自动计算大小
4>:malloc\free申请空间时,以字节为单位,而new\delete申请空间时,以数据类型为单位
5:new申请空间时可以给空间进行初始化,而malloc不可以
6: malloc申请出的空间结果是void*类型,使用时需要根据具体的情况进行强转,而new申请空间时,申请什么类型的空间返回的就是什么类型的指针
7:new申请对象空间时,会自动调用该对象所在类中的构造函数,而malloc不会
8:delete释放对象空间时,会自动调用该对象所在类的析构函数,而free不会
9:在new和delete的底层实现中,还是调用了c语言中的malloc、free
内存泄漏怎么产生的?如何避免?
产生原因:
1:在使用 new 或 malloc 动态分配内存后,如果没有使用 delete 或 free 释放内存,就会导致内存泄漏;
2:在重新分配内存时,如果没有释放原有的内存,可能会导致内存泄漏。
3:在异常发生时,如果没有适当的内存释放机制,可能会导致内存泄漏。
4:没有正确管理内部指针,可能会导致内存泄漏
如何避免:
1:使用 new 或 malloc 分配内存后,确保在适当的地方使用 delete 或 free 释放内存。
2:在重新分配内存之前,确保释放原有的内存。
C++的内存分区
主要分区有
栈:栈是用于存储局部变量和函数调用信息的内存区域。
栈的特点:是栈内存由编译器自动分配和释放,函数调用结束后,局部变量的内存会自动释放。栈的分配和释放速度非常快,因为只需移动栈指针。栈的大小通常较小,受操作系统限制,过多的递归调用或大数组可能导致栈溢出
堆:堆是用于动态内存分配的内存区域
堆的特点:堆内存需要程序员手动分配(使用 new 或 malloc)和释放(使用 delete 或 free;
堆的大小仅受系统内存限制,可以动态分配任意大小的内存;由于需要管理内存分配和释放,堆的分配和释放速度相对较慢;如果忘记释放堆内存,可能导致内存泄漏。
C数据段:数据段用于存储全局变量和静态变量。
C数据段特点:储已初始化的全局变量和静态变量;存储未初始化的全局变量和静态变量;
代码段:代码段存储程序的可执行代码
代码段特点:代码段通常是只读的,以防止程序在运行时修改自身的代码;多个进程可以共享同一段代码,节省内存
总结:
栈:用于存储局部变量和函数调用信息,自动管理,速度快,但大小有限。
堆:用于动态内存分配,灵活性高,但需要手动管理,速度较慢,存在内存泄漏风险。
数据段:存储全局变量和静态变量,分为初始化和未初始化部分。
代码段:存储程序的可执行代码,通常是只读的。
说说你常用的设计模式和应用场景
常用的数据结构有哪些?时间复杂度和空间复杂度如何使用?
数组:时间复杂度:O(1);空间复杂度:O(n),n为数组的大小
链表:时间复杂度:O(n) 空间复杂度:O(n)
栈:时间复杂度:O(1);空间复杂度:O(n)
队列:时间复杂度:O(1);空间复杂度:O(n)
哈希表:时间复杂度:O(1),空间复杂度:O(n)
二叉树::O(log n);空间复杂度:O(n)
图:时间复杂度:
查找边:O(V + E)(V为顶点数,E为边数)
插入边:O(1)(在邻接表中)
删除边:O(E)(在邻接表中)
空间复杂度:O(V + E),V为顶点数,E为边数。
集合:时间复杂度:O(1);空间复杂度:O(n)