1.内存分配方式有哪几种?
i.从堆区分配。也叫做动态内存申请。可以使用malloc或者new动态的从堆区申请任意数量的内存,由程序员决定是否delete或free释放内存。
ii.从栈区分配。函数在执行过程中,函数内的局部变量的存储单元从栈区分配,函数执行完后这些存储单元会自动释放。从栈区分配存储单元的运算操作内置于处理器的指令集中,效率很高,但分配的内存容量有限。
iii.从全局存储区分配。内存在程序的编译阶段就已经分配好了,该内存在程序的整个运行期间都有效,如static静态变量、全局变量。
2.vector和list使用场景的区别
vector拥有一块连续的内存,适合应用于高效率的访问,而不在乎插入和删除的效率的场景。
list拥有不连续的内存空间,适合应用于高效的插入和删除,而不关心访问效率的场景。
3.说说多态
如果说重载是多态的一种,那么多态分为静态多态和动态多态。
动态多态是子类重写父类虚函数实现的,是在运行期间就决定了要调用哪个函数,因此称为动态多态。
静态多态其实就是重载,是因为静态多态在编译期间就决定了要调用哪个函数,根据参数列表来决定。
如果不做区分,一般我们说的多态就是动态多态。
动态多态的实现与虚函数表、虚函数指针有关。
4.说说const的几个作用
①修饰普通类型变量。告诉编译器该变量的值保持不变。
②修饰指针变量。根据const所在的位置和出现的次数又分三种类型。
i.指向常量的指针。用来防止修改指向指针指向的值。
如:
const int *a 和int const *a
ii.常指针。将指针声明为常量,用来防止修改指针的指向。
如:
int *const a;
iii.指向常量的常指针。用来防止修改指针的指向和指向的常量的值。
const int *const a;
③修饰参数传递。
④修饰函数返回值。
⑤修饰成员函数。
5.指针和引用的区别
(1)指针是实体,占用内存空间,引用是别名,与对象共享内存空间。
(2)有二级指针,没有二级引用。
(3)sizeof(指针)是指针的大小,sizeof(引用)是引用对象的大小。
(4)指针使用时需要解引用,引用不需要。
(5)指针不用初始化或初始化为NULL,引用定义时必须初始化。
(6)如果返回的是动态分配的内存或对象,必须用指针,用引用会造成内存泄漏。
(7)指针可以修改指向,引用不可以。
6.虚函数和纯虚函数
①虚函数的工作机制
虚函数的实现原理是虚函数表和虚表指针。
若类中存在虚函数,则编译器会创建一个虚函数表,虚函数表是一个数组,数组中的元素存放着类中虚函数的地址。
同时会为每一个类的对象添加一个隐藏成员,该隐藏成员保存着指向虚函数表的指针。该隐藏成员占据着对象在内存布局的最前端。
所以虚函数表只有一份,而有多少个对象就有多少个虚函数表指针。
②纯虚函数了解吗?什么情况下使用?
i.纯虚函数是在基类中声明的虚函数,它要求所有派生类必须定义自己的实现方法,以实现多态性。
ii.实现了纯虚函数的子类,纯虚函数在子类中变成了虚函数。
iii.定义纯虚函数是为了实现一个接口,用来规范派生类的行为,也即规范继承这个类的程序员必须实现这个函数。
iv.包含纯虚函数的类叫做抽象类,之所以说它抽象,是因为无法实例化,也即是无法创建对象。原因在于,纯虚函数不是完整的函数,无法调用,也无法为其分配内存空间。
v.抽象函数通常作为基类,让派生类实现纯虚函数。派生类只有实现纯虚函数才能被实例化。