alin的学习之路:面试题 C/C++相关
-
c++虚函数原理
- 加上virtual关键字后,父类的结构发生了改变,在原有的基础上增加了一个指向虚函数表的指针
- 虚函数表中存放的是虚函数的地址,父类的地址结构中放的是这个虚函数的地址
- 当子类重写父类的虚函数时,虚函数表中的函数地址发生了改变,变为了重写的函数的地址,从而可以对其进行调用
-
智能指针
- 智能指针是存储指向动态分配(堆)对象指针的类。能够在适当的时间自动删除指向的对象。智能指针在面对异常的时候格外有用,因为他们能够确保正确的销毁动态分配的对象。他们也可以用于跟踪被多用户共享的动态分配对象。
- 使用智能指针,从而实现指针指向的对象的共享。
- 引入智能指针可以防止出现悬垂指针的情况,一般是把指针封装到一个称之为智能指针类中,这个类中另外还封装了一个使用计数器,对指针的复制等操作将导致该计数器的值加1,对指针的delete操作则会减1,值为0时,指针为NULL
-
c语言如何实现c++对象以及私有成员
- 使用struct结构体实现封装,类中的一些方法可以使用函数指针变量来代替
- 私有成员可以使用void*对结构体变量进行修饰,从而隐藏掉其真实的类型,达到私有成员的效果,真实的类型只有开发者才知道
-
c++多态实现
- C++的多态分为静态多态和动态多态
- 静态多态和动态多态的区别就是函数地址是早绑定(静态联编)还是晚绑定(动态联编)。如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态),就是说地址是早绑定的。而如果函数的调用地址不能编译不能在编译期间确定,而需要在运行时才能决定,这这就属于晚绑定(动态多态,运行时多态)。
- 实现方法:子类重写父类的虚函数,地址绑定称为子类的函数地址
-
new和malloc的区别以及底层实现原理
- 区别
- new带有内置的长度计算、类型转换和安全检查。
- new 当创建一个对象数组的时候,必须对数组中的每一个对象调用构造函数
- new 对应 delete ,malloc 对应 free
- new 是一个运算符 malloc 是一个函数
- 返回值:new返回对应类型指针,malloc返回void*
- 分配失败:new 分配失败时会抛出异常,malloc是返回NULL
- 底层实现:
new
操作符从自由存储区(free store)
上为对象动态分配内存空间,而malloc
函数从堆上动态分配内存。自由存储区是C++
基于new
操作符的一个抽象概念,凡是通过new
操作符进行内存申请,该内存即为自由存储区。- malloc 调用时,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用
malloc
函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。
- 区别
-
STL中的vector怎么扩容
- 底层是使用realloc
- 扩容机制是根据特定的算法来的,每当容量剩余达到一定数量时,就会根据当前容量进行扩容
-
虚函数指针的初始化过程
- 在基类的构造函数被调用之后,自定义代码调用之前
- 构造过程中,首先在基类的构造函数中,会把虚函数指针初始化为指向基类的虚函数表,然后,在子类构造函数中又覆盖为指向子类的虚函数表,层层覆盖,最后虚函数指针会正确指向构造的类的虚函数表。
- 由于虚函数指针初始化代码是在自定义代码之前,这意味着我们可以在自定义代码的构造函数中调用该类的虚函数。
-
c++11原子变量介绍
- atomics
-
c++11特性有哪些,说用过的
- lambda表达式
- 模板技术
template<class T>
-
怎么理解重载与重写
- 重载是不同的函数
- 重写是指子类继承父类后的重写
-
怎么理解c++中的static关键字
- 只初始化一次
-
vector和list 的区别
- vector是连续存储的数组
- list是链表形式,数据的存储内存地址不连续
-
c++的内存分配
- 在C++中内存分为5个区,分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
- **堆:**堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
- **栈:**在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
- **自由存储区:**自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区
- **全局/静态存储区:**这块内存是在程序编译的时候就已经分配好的,在程序整个运行期间都存在。例如全局变量,静态变量。
- **常量存储区:**这是一块比较特殊的存储区,他们里面存放的是常量(const),不允许修改。
-
map与set的底层实现
-
红黑树
-
map和set容器内的所有元素都是以节点方式来存储的,其节点结构和链表类似,指向父节点和子节点。
因此,在插入的时候只需要稍作变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍作变换后吧指向删除节点的节点的指针指向其他的节点就可以了。
这其中,只涉及到指针的转换,而没有涉及到内存的移动。
-
-
类静态变量的初始化
- 需要在类内声明,类外初始化
-
析构函数可以是虚函数?为什么
-
析构函数可以为虚函数,也可以不为虚函数。(更多的时候不为虚函数)。默认不为虚函数。
设计析构函数为虚函数,主要是考虑到继承。 -
当A为基类,B为A的继承类,考虑如下情况: A *p = new B(); ..... delete p; 此时如果析构函数不是虚函数,那么delete p会执行A的析构函数,而不是B的,这样会造成B的函数资源没有释放
-
-
深拷贝与浅拷贝
- 深拷贝和浅拷贝的问题主要发生在指针上
- 浅拷贝指的是只拷贝了指针的值,而并未拷贝指针指向的内容
- 深拷贝指的是重新申请一块内容,并且将原指针指向的内容拷贝一份到新的指针里面
-
指针常量,常量指针的区别
- 指针常量 * const :指针的指向不能发生修改。
- 常量指针 const * :指针指向的值不能直接发生修改。
-
指针与引用的区别
-
引用的底层是操作受限的指针,不能修改指向等等。
-
指针是一个变量,存储的是指向内容的地址。引用相当于是一个变量的别名。
-
引用不可以为空,创建必须初始化。指针可以为空,可以在需要使用的时候进行初始化。
-
指针可以有多级,引用只有一级。
-