C++中高级面试题集锦
[TOC]
概述
文章参考:https://mp.weixin.qq.com/s/B4zQhTxl8EL0astDch-G0w
C++ 是什么?
C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛。C++支持多种编程范式: 面向对象编程、泛型编程和过程化编程。 其编程领域众广,常用于系统开发,引擎开发等应用领域,是最受广大程序员受用的最强大编程语言之一,支持类:类、封装、重载等特性!
C和C++的区别?
C++在C的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。
C++面向对象
什么是面向对象(OOP)?
面向对象是一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。
C++面向对象的特点
封装、继承、多态
什么是多态?
多态是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态。
子类析构时要调用父类的析构函数吗?
析构函数调用的次序是先派生类的析构后基类的析构,也就是说在基类的的析构调用的时候,派生类的信息已经全部销毁了。
定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数。
多态、虚函数、纯虚函数
多态:是对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面:在程序运行时的多态性通过继承和虚函数来体现;
在程序编译时多态性体现在函数和运算符的重载上;
虚函数:在基类中冠以关键字 virtual 的成员函数。它提供了一种接口界面。允许在派生类中对基类的虚函数重新定义。
STL库用过吗?常见的STL容器有哪些?算法用过哪几个?
STL包括两部分内容:容器和算法。(重要的还有融合这二者的迭代器)
容器,即存放数据的地方。比如array等。
在STL中,容器分为两类:序列式容器和关联式容器。
序列式容器,其中的元素不一定有序,但都可以被排序。如:vector、list、deque、stack、queue、heap、priority_queue、slist;
关联式容器,内部结构基本上是一颗平衡二叉树。所谓关联,指每个元素都有一个键值和一个实值,元素按照一定的规则存放。如:RB-tree、set、map、multiset、multimap、hashtable、hash_set、hash_map、hash_multiset、hash_multimap。
下面各选取一个作为说明。
vector:它是一个动态分配存储空间的容器。区别于c++中的array,array分配的空间是静态的,分配之后不能被改变,而vector会自动重分配(扩展)空间。
set:其内部元素会根据元素的键值自动被排序。区别于map,它的键值就是实值,而map可以同时拥有不同的键值和实值。
算法,如排序,复制……以及个容器特定的算法。这点不用过多介绍,主要看下面迭代器的内容。
迭代器是STL的精髓,我们这样描述它:迭代器提供了一种方法,使它能够按照顺序访问某个容器所含的各个元素,但无需暴露该容器的内部结构。它将容器和算法分开,好让这二者独立设计。
const知道吗?解释其作用。
解释C++中静态函数和静态变量?
(1)类静态数据成员在编译时创建并初始化:在该类的任何对象建立之前就存在,不属于任何对象,而非静态类成员变量则是属于对象所有的。类静态数据成员只有一个拷贝,为所有此类的对象所共享。
(2)类静态成员函数属于整个类,不属于某个对象,由该类所有对象共享。
1、static 成员变量实现了同类对象间信息共享。
2、static 成员类外存储,求类大小,并不包含在内。
3、static 成员是命名空间属于类的全局变量,存储在 data 区的rw段。
4、static 成员只能类外初始化。
5、可以通过类名访问(无对象生成时亦可),也可以通过对象访问。
C++内存模型
说下你对C++中内存的了解?
栈 :由编译器自动分配释放。在需要的时候由编译器自动分配空间,在不需要的时候由编译器自动释放空间。一般用于保存局部变量和函数参数。连续的内存空间,在函数调用的时候,首先入栈的主函数的下一条可执行指令的地址,然后是函数的哥哥参数。大多数编译器中,参数是从右向左入栈(原因是采用这种殊勋,是为了让程序员在使用C/C++的函数参数长度可变这个特性时更加方便。如果是从左向右压栈第一个参数(即描述可变参数表各变量类型的哪个参数)将被放在占地,由于可变参数的函数第一步就需要解析可变参数表的各个参数类型,即第一步就需要得到上述参数,因此将他放在栈底是不方便的)本地函数调用结束时,局部变量先出站,然后是参数,最后是栈顶指针最开始存放的地址,程序由该点继续运行,不会产生碎片。栈是高地址向低地址扩展,栈底高地址,空间较小。
堆 :一般由程序员分配释放,需要手动new malloc delete free进行分配和回收。若程序员不释放,会造成内存泄露的问题。不连续的空间,实际上系统中有一个空闲链表,当有程序申请的时候,系统会遍历空闲链表找到第一个大约等于申请大小的空间分配给程序,一般在分配程序的时候,也会空间头部写入内存大小,方便delete回收空间大小。当然,如果有剩余的,也会将剩余的插入到空闲链表中。这也是产生内存碎片的原因。
全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束释放
另外还有一个专门放常量的地方。- 程序结束释放
程序代码区,存放2进制代码。
在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的”adgfdf”这样的字符串存放在常量区。
new和malloc的区别?
1、malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2、对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。
3、由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
4、C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
5、new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。
delete与delete[]区别
delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。
在More Effective C++中有更为详细的解释:“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用 operator delete 来释放内存。”delete与new配套,delete []与new []配套
1 | MemTest *mTest1 = new MemTest[10]; |
内建简单数据类型,delete和delete[]功能是相同的。
对于自定义的复杂数据类型,delete和delete[]不能互用。delete[]删除一个数组,delete删除一个指针。
简单来说,用new分配的内存用delete删除;用new[]分配的内存用delete[]删除。delete[]会调用数组元素的析构函数。
内部数据类型没有析构函数,所以问题不大。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组。
C++智能指针
1. 说一下你理解的C++四种智能指针
2. C++指针和引用的区别
指针和引用都是一种内存地址的概念,区别就是指针是一个实体,引用只是一个别名。
在程序编译的时候,指针和引用会被添加到符号表中
指针它指向一块内存,指针的内容就是它所指向的变量的内存地址,在编译的时候,则是将“指针变量名-指针变量地址”添加到符号表中。所以说,指针包含的内容其实是可以改变的,允许拷贝和赋值。有const和非const的区别,甚至可以为空。sizeof指针得到的就是指针类型的大小。
而对于引用类说,他只是一块内存的别名,在添加符号表的时候,是将“应用变量名-引用对象地址”添加到符号表中,符号表一经完成不能改变,所以引用必须而且只能在定义的时候被绑定到一块内存上,后续不能更改,也不能为空。也没有const和非const区别。