目录

11、请你说说什么情况会调用拷贝构造,什么时候会调用赋值操作

12、请你说说虚函数可以是内联函数吗

13、请你说说虚函数和纯虚函数的区别

14、为什么将析构函数设置成虚函数

15、简述一下 C++ 中的四种类型转换

16、说一说 STL 中有哪些常见的容器

17、STL 容器用过哪些,查找的时间复杂度是多少,为什么?

18、请你说说 STL 中容器的类型,每种分别有哪些容器

19、说一说 vector 和 list 的区别,分别适用于什么场景?

20、简述 vector 的实现原理


11、请你说说什么情况会调用拷贝构造,什么时候会调用赋值操作

拷贝构造函数用于创建新对象时,用一个已存在的同类型对象初始化该新对象,例如:用已有对象初始化新对象(A a(b);A a = b;)、对象按值作为函数参数传递、函数按值返回对象;而赋值操作符(operator=)用于两个已存在的对象之间的赋值操作,例如对已初始化的对象直接赋值(a = b;)。核心区别是:拷贝构造针对新对象的初始化,赋值操作针对已有对象的更新。

12、请你说说虚函数可以是内联函数吗

得分点 编译期、运行期 标准回答 1. 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。 2. 内联是在编译期建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时不可以内联。 3. inline virtual 唯一可以内联的时候是:编译器知道所调用的对象是哪个类,这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。

13、请你说说虚函数和纯虚函数的区别

得分点 定义格式、特点、作用 标准回答 1. 格式 虚函数的定义格式为:virtual 返回值类型 函数名(参数列表) {} 纯虚函数的定义格式为:virtual 返回值类型 函数名(参数列表) = 0; 2. 特点 虚函数可以有具体的实现,纯虚函数没有具体的实现。 对于虚函数来说,父类和子类都有各自的版本,由多态方式调用的时候动态绑定。 有纯虚函数的类称为抽象类,有纯虚函数的类不能实例化,派生类必须实现纯虚函数才可以实例化,否则也是抽象类。 3. 作用 虚函数是 C++ 中用于实现动态多态的机制。 很多情况下,在基类中不能对虚函数给出具体的有意义的实现,就可以把它声明为纯虚函数,它的实现留给该基类的派生类去做。

14、为什么将析构函数设置成虚函数

得分点 概念、防止内存泄露 标准回答 1. 概念 虚析构函数,是将基类的析构函数声明为 virtual class Base { public: Base() { } // 虚析构函数 virtual ~Base() { } } 2. 作用 虚析构函数的主要作用是为了防止遗漏资源的释放,防止内存泄露。如果基类中的析构函数没有声明为虚函数,基类指针指向派生类对象时,则当基类指针释放时不会调用派生类对象的析构函数,而是调用基类的析构函数,如果派生类析构函数中做了某些释放资源的操作,则这时就会造成内存泄露。

15、简述一下 C++ 中的四种类型转换

得分点 static_cast、dynamic_cast、const_cast、reinterpret_cast 标准回答 使用 C 风格的类型转换可以把想要的任何东西转换成我们需要的类型,但是这种类型转换太过松散,对于这种松散的情况,C++ 提供了更严格的类型转换,可以提供更好的控制转换过程,并添加 4 个类型转换运算符,使转换过程更规范:static_cast、dynamic_cast、const_cast、reinterpret_cast。 1. static_cast 静态转换 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换 - 进行上行转换(把派生类的指针或引用转换成基类表示)是安全的 - 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的 用于基本数据类型之间的转换,如把 int 转换成 char,把 char 转换成 int。这种转换的安全性也要开发人员来保证 2. dynamic_cast 动态转换 dynamic_cast 主要用于类层次间的上行转换和下行转换 在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的 在进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全 3. const_cast 常量转换 该运算符用来修改类型的const属性 常量指针被转化成非常量指针,并且仍然指向原来的对象 常量引用被转换成非常量引用,并且仍然指向原来的对象 注意:不能直接对非指针和非引用的变量使用 const_cast 操作符 4. reinterpret_cast 重新解释转换 这是最不安全的一种转换机制,最有可能出问题 主要用于将一种数据类型从一种类型转换为另一种类型,它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针

16、说一说 STL 中有哪些常见的容器

得分点 顺序容器、关联式容器、容器适配器 标准回答 STL 中容器分为顺序容器、关联式容器、容器适配器三种类型,三种类型容器特性分别如下: 1. 顺序容器 容器并非排序的,元素的插入位置同元素的值无关,包含 vector、deque、list。 - vector:动态数组 元素在内存连续存放。随机存取任何元素都能在常数时间完成。在尾端增删元素具有较佳的性能。 - deque:双向队列 元素在内存连续存放。随机存取任何元素都能在常数时间完成(仅次于 vector )。在两端增删元素具有较佳的性能(大部分情况下是常数时间)。 - list:双向链表 元素在内存不连续存放。在任何位置增删元素都能在常数时间完成。不支持随机存取。 2. 关联式容器 元素是排序的;插入任何元素,都按相应的排序规则来确定其位置;在查找时具有非常好的性能;通常以平衡二叉树的方式实现,包含set、multiset、map、multimap。 - set/multiset set中不允许相同元素,multiset 中允许存在相同元素。 - map/multimap map 与 set 的不同在于 map 中存放的元素有且仅有两个成员变,一个名为 first,另一个名为 second,map 根据 first 值对元素从小到大排序,并可快速地根据 first 来检索元素。map 和multimap 的不同在于是否允许相同 first 值的元素。 3. 容器适配器 封装了一些基本的容器,使之具备了新的函数功能,包含 stack、queue、priority_queue。 - stack:栈 栈是项的有限序列,并满足序列中被删除、检索和修改的项只能是最进插入序列的项(栈顶的项),后进先出。 - queue:队列 插入只可以在尾部进行,删除、检索和修改只允许从头部进行,先进先出。 - priority_queue:优先级队列 内部维持某种有序,然后确保优先级最高的元素总是位于头部,最高优先级元素总是第一个出列。

17、STL 容器用过哪些,查找的时间复杂度是多少,为什么?

标准回答 STL 中常用的容器有 vector、deque、list、map、set、multimap、multiset、unordered_map、unordered_set 等。容器底层实现方式及时间复杂度分别如下: 1. vector 采用一维数组实现,元素在内存连续存放,不同操作的时间复杂度为: 插入: O(N) 查看: O(1) 删除: O(N) 2. deque 采用双向队列实现,元素在内存连续存放,不同操作的时间复杂度为: 插入: O(N) 查看: O(1) 删除: O(N) 3. list 采用双向链表实现,元素存放在堆中,不同操作的时间复杂度为: 插入: O(1) 查看: O(N) 删除: O(1) 4. map、set、multimap、multiset 上述四种容器采用红黑树实现,红黑树是平衡二叉树的一种。不同操作的时间复杂度近似为: 插入: O(logN) 查看: O(logN) 删除: O(logN) 5. unordered_map、unordered_set、unordered_multimap、 unordered_multiset 上述四种容器采用哈希表实现,不同操作的时间复杂度为: 插入: O(1),最坏情况O(N) 查看: O(1),最坏情况O(N) 删除: O(1),最坏情况O(N) 注意:容器的时间复杂度取决于其底层实现方式。

18、请你说说 STL 中容器的类型,每种分别有哪些容器

得分点 序列式容器、关联式容器、无序关联式容器、容器适配器 标准回答 STL 中容器的类型和每种类型的容器如下: 1. 序列式容器 array、vector、deque、list、forward_list 2. 关联式容器 map、multimap、set、multiset 3. 无序关联式容器 unordered_map、unordered_multimap、unordered_set、unordered_multiset 4. 容器适配器 stack、queue、priority_queue

19、说一说 vector 和 list 的区别,分别适用于什么场景?

得分点 低层数据结构、内存顺序、是否支持随机访问 标准回答 1. 区别 - vector 底层实现是数组,list 是双向链表 - vector 支持随机访问,list 不支持 - vector 是顺序内存,list 不是 - vector 在中间节点进行插入删除会导致内存拷贝,list 不会 - vector 一次性分配好内存,不够时才进行扩容,list 每次插入新节点都会进行内存申请 - vector 随机访问性能好,插入删除性能差,list 随机访问性能差,插入删除性能好 2. 适用场景 - vecto r拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用 vector。 - list 拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。

20、简述 vector 的实现原理

得分点 动态数组、连续存储空间、扩容 标准回答 vector 是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问,由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。 当 vector 的大小和容量相等(size==capacity)也就是满载时,如果再向其添加元素,那么 vector 就需要扩容。vector 容器扩容的过程需要经历以下 3 步: 1. 完全弃用现有的内存空间,重新申请更大的内存空间; 2. 将旧内存空间中的数据,按原有顺序移动到新的内存空间中; 3. 最后将旧的内存空间释放。 vector 扩容是非常耗时的。为了降低再次分配内存空间时的成本,每次扩容时 vector 都会申请比用户需求量更多的内存空间(这也就是 vector 容量的由来,即 capacity>=size),以便后期使用。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐