腾讯PC客户端面经
1.有关虚函数调用问题
空指针可以在特定的情况下去调用非虚函数,因为非虚函数在编译阶段就可以确定地址,调用的时候this指针传的是nullptr没有问题,不需要依赖对象的创建。
空指针不可以去调用虚函数,因为虚函数的调用需要虚表,对象通过虚表指针才能找到虚表,虚表指针的初始化是在构造函数中进行的,根据上面的推理链,nullptr不会创建对象,没有调用构造函数,所以虚表指针没有被复制,找不到虚表,故无法调用虚函数。
#include <iostream>using namespace std;class A
{
public:void func(){cout << "1" << endl;cout << a_ << endl;}virtual void v_func(){cout << "2" << endl;}
private:int a_;
};
int main()
{A* ptr = nullptr;/* <空指针调用非虚函数>* 非虚函数在编译阶段就已经确定了函数的地址,不依赖于对象的实例(这个对象是否被创建)。* 编译器把成员函数调用转换为普通函数 A::func(ptr), 对象的地址作为隐含参数传递过去 nullptr* 但是这种空指针访问非虚函数的方式仍然存在极大的风险,例如如果在函数内部调用了成员变量,回造成* 空指针访问的问题*/ptr->func();/* <空指针调用虚函数>* 虚函数的调用需要虚表, 每个类都有一个虚表,但是类有多个对象,每个对象都有一个虚表指针存储虚函数的* 地址从而找到虚表,虚表指针是在构造函数中赋值的,那么就存在一个问题,如果是空指针那么并没有创建* 对象的实例,没有办法去调用构造函数,也就没有办法给虚表指针赋值,找不到虚表也就无法调用虚函数*/ptr->v_func();return 0;
}
2.创建一个类,编译器会默认提供哪些函数?
C++98
默认构造、默认析构、默认拷贝构造、默认赋值运算符重载
C++11
默认移动构造、默认移动运算符重载
C++11后,如果自定义了的析构函数,系统将不会提供默认移动构造 、移动赋值
3.string类型在构造函数中赋值和初始化参数列表中初始化的区别
首先明确一个调用顺序问题,是先调用初始化参数列表,给成员变量进行初始化,如果没在初始化参数列表中的成员变量会调用它们的默认构造。然后是进入构造函数的函数体中,对成员变量进行赋值。
比如string举例,如果在初始化参数列表中,会调用string类的特定构造函数进行初始化。
但是如果在构造函数中赋值,需要先调用stirng类的默认构造进行默认初始化,然后再进行赋值,效率会低很多。
4.菱形继承中,各个类的虚函数表有什么变化
比如现在有A B C D四个类,A类是B、C的基类,D类多继承于B类、C类。满足菱形继承关系。
假设现在A中有一个func1函数,且是虚函数。
B、C、D中分别重载了该函数
A:A::func1
B:B::func1
C: C::func1
D: 两个虚表,一个从B继承而来,一个从C继承而来。
5.虚继承如何解决菱形继承二义性问题的
A、B、C、D。
那么虚继承指的是,B类C类虚继承于A,A作为虚基类。此时BC继承过来的不再是A中的变量,而是一个虚基表指针,里面存储着虚基表的地址,虚基表里面存折虚基表指针到A类中成员地址的偏移量。故通过虚基表指针 + 偏移量就可以找到虚基类的成员变量
这样D类在继承的时候,有两份虚基表指针,无论是使用B的,还是使用C的找到的都是唯一的成员变量。不会产生二义性问题啦
6.C++中四种类型转换
static_cast【提供的是编译器认为安全的类型转换】
基本数据类型之间的转换
向上转换
dynamic_cast
向下转换
这个过程会有安全检查,具体是如何检查的呐,方法如下:
1.检查该对象是否有虚函数,如果没有虚函数,就找不到虚表,无法通过RTTI找到对象的实际类型信息
2.获取对象的实际类型信息
3.比较实际类型信息于目标类型信息,如果是一样的,转换成功
如果目标类型信息是实际类型信息的基类,也是转换成功的
其他情况返回一个nullptr指针
const_cast
去常转换
通常用于指针或者引用
const int a = 10
const_cast(a) false
7.weak_ptr在lock,获取shared_ptr的时候,怎么判断是否获取成功?
lock函数核心是去获取所引用的shared_ptr的引用计数,如果发现引用计数 > 0,说明托管的对象还在,反之说明托管的对象已经被释放了,那么lock函数返回一个空就好了
8.STL-deque底层的数据结构是什么?
一个指针数组 + 若干个固定大小的缓冲区
MAP_SIZE = 2
QUEUE_SIZE 4096 / sizeof(T)
9.现在又一个文本编译器,要求尽可能的保存用户在编辑器中的数据,因为系统可能随时崩溃,我们又什么办法,将用户的数据保存下来呐?
定时自动保存:起一个定时器
实时保存:没输入一个字符,或者进行一次编译的时候,都去进行一个保存操作
增量保存:只保存用户对文本所做的增量修改,而不是整个文本内容。这样可以减少保存的数据量,提高保存效率。
备份文件:除了正常保存的文件外,定期创建备份文件。备份文件可以保存到不同的磁盘分区或外部存储设备,以防止本地磁盘故障导致数据丢失。