微信搜索“编程笔记本”,获取更多信息
------------- codingbook2020 -------------
面经面经面经!今天分享的是 CVTE 视源股份的 C++ 软件开发的一面面试题,CVTE 的面试题是真的多!面对疾风吧!!!
面试题
文章目录
-
-
- 面试题
- 1.1 C++ 的三大特性是什么?什么是多态?
- 1.2 虚函数的工作原理?
- 1.3 如果是多重继承只有一个虚表指针吗
- 1.4 使用过类模板吗?函数模板和类模板的区别是什么?
- 1.5 用过哪些 STL 特性?
- 1.6 vector 的扩容原理?
- 1.7 如果让你实现 vector 动态删除后容量缩小你会如何设计?
- 1.8 了解过类型萃取吗?
- 1.9 了解过 C++11 新特性吗?
- 1.10 C++ 有哪些创建线程的方式?
- 1.11 了解过智能指针吗?智能指针怎么解决内存泄漏?weak_ptr 怎么解决循环引用的问题?
- 1.12 TCP 滑动窗口的原理?
- 1.13 TCP 和 UDP 的区别?
- 1.14 为什么 TCP 连接不是两次握手?为什么要四次挥手而不是三次?
- 1.15 怎么解决 TCP 粘包问题?
- 1.16 怎么判断一个链表是否有环,写出代码?
-
1.1 C++ 的三大特性是什么?什么是多态?
C++ 的三大特性是封装性、继承性、多态性。
- 封装性
C++语言中支持数据封装,类是支持数据封装的工具,对象是数据封装的实现。所谓封装具有两方面的含义:一是将有关的数据和操作代码封装在一个对象中,各个对象相互独立,互不干扰。二是将对象中某些数据与操作代码对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界消息。 - 继承性
一个类(基类)可以根据需要生成它的派生类,派生类还可以再生成派生类。继承机制允许派生类继承基类的数据和操作,也就是说允许派生类使用基类的数据和操作,同时派生类还可以增加新的数据和操作。 - 多态性
面向对象中的多态性指的是不同的对象收到相同的消息时产生多种不同的行为。实现多态的方法主要两种,一种是编译时多态,主要由重载和模板来实现;一种是运行时多态,主要由虚函数(包括继承)来实现。
1.2 虚函数的工作原理?
C++ 中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数。
当子类重新定义了父类的虚函数后,当父类的指针指向子类对象的地址时,父类指针根据赋给它的不同子类指针,动态地调用子类的该函数,而不是父类的函数,且这样的函数调用发生在运行阶段,而不是发生在编译阶段,称为动态联编。
更通俗地说就是:如果使用了 virtual 关键字,程序将根据引用或指针指向的对象类型来选择方法,否则使用引用类型或指针类型来选择方法。
请看一个例子:
#include <iostream>
using namespace std;
class Father {
public:
virtual void show() {
cout << "This is class Father" << endl;
}
};
class Son : public Father {
public:
void show() {
cout << "This is class Son" << endl;
}
};
int main()
{
Father *f = new Son;
f->show();
return 0;
}
/*
编译运行:
jincheng@jincheng-PC:~/Desktop$ g++ -o test test.cpp
jincheng@jincheng-PC:~/Desktop$ ./test
This is class Son
*/
可以看到,父类指针根据赋给其的具体子类指针,调用子类的方法,而非父类的方法。若父类中的该方法未声明为 virtual ,则父类指针只会调用父类方法。请看下面的例子:
#include <iostream>
using namespace std;
class Father {
public:
// virtual void show() {
void show() {
cout << "This is class Father" << endl;
}
};
class Son : public Father {
public:
void show() {
cout << "This is class Son" << endl;
}
};
int main()
{
Father *f = new Son;
f->show();
return 0;
}
/*
编译运行:
jincheng@jincheng-PC:~/Desktop$ g++ -o test test.cpp
jincheng@jincheng-PC:~/Desktop$ ./test
This is class Father
*/
介绍完虚函数的功能后,我们再来看一下虚函数是如何工作的。
编译器处理虚函数的方法是:为每个类对象添加一个隐藏成员,隐藏成员中保存了一个指向数组的指针,数组的元素是函数地址,这种数组成为虚函数表,这样的指针称为虚表指针。即,每个类使用一个虚函数表,每个类对象使用一个虚表指针。
举个例子:基类对象包含一个虚表指针,指向基类中所有虚函数的地址表。派生类对象也将包含一个虚表指针,指向派生类虚函数表。看下面两种情况:
- 如果派生类重写了基类的虚方法,该派生类虚函数表将保存重写的虚函数的地址,而不是基类的虚函数地址。
- 如果基类中的虚方法没有在派生类中重写,那么派生类将继承基类中的虚方法,而且派生类中虚函数表将保存基类中未被重写的虚函数的地址。
- 如果派生类中定义了新的虚方法,则该虚函数的地址也将被添加到派生类虚函数表中。
通过上面的分析我们知道了虚函数的引入是为了实现运行时多态,也了解到虚函数的调用比普通函数的开销要大(查表)。
有关虚函数在析构函数中的使用,参见往期笔记:面试 C++ 工程师:为什么析构函数必须是虚函数?为什么默认的析构函数不是虚函数?
1.3 如果是多重继承只有一个虚表指针吗
在多继承情况下,有多少个含有虚函数的基类就有多少个虚函数表和虚表指针。
1.4 使用过类模板吗?函数模板和类模板的区别是什么?
类模板
所谓类模板,实际上是建立一个通用类,其数据成员、成员函数的返回值类型和形参类型不具体指定,用一个虚拟的类型来代表。使用类模板定义对象时,系统会根据实参的类型来取代类模板中虚拟类型从而实现了不同类的功能。
其框架如下:
template<class T, class V>
class Class_Name {
public:
T func_name(T a, V b) {
//
}
private:
T val;
V *p;
}
或者
template<typename T, typename V>
class Class_Name {
public:
T func_name(T a, V b) {
//
}
private:
T val;
V *p;