美文网首页C++面试
C++面试题整理

C++面试题整理

作者: 猿哥媛姐 | 来源:发表于2018-03-15 09:14 被阅读181次

    1.数组名和指针的区别?

    明确一点数组名不是指针,可以通过sizeof来验证。其本质是指代数组这样一个数据结构。

    数组名在表现很像const指针指针,不可以被改变(被赋值,++,--),可以用*来取对象,作为指针参数,可以+整数

    做为形参的数组名失去了其数据结构的本质内涵,其本质是一个指针。

    2.引用类型和指针的区别

    从反汇编的角度看,引用的本质是一个由编译器管理的指针。其表现出来的语法特征和其所引用的对象一致。

    作为函数参数时,和指针一样,真正传递的是指针,而非对象的拷贝,较少了堆栈空间的使用,而且可以在函数体内可以对所指的对象进行修改。

    引用不可以被修改,以失去了指针的灵活性为代价,提高了程序安全性。

    3.const总结

    const的作用是希望通过对指定const属性,保证变量不被错误修改,提高代码的安全性。

    修饰变量:变成了常量,不可以被修改,其他操作不受影响。编译器在编译时将用到该变量的地方替换成对应的值。与#define的替换相比,const保留了变量的类型属性,可以做类型检验。

    修饰指针:作用在指针本身,则该指针不能被修改(const指针),所以必须初始化;作用在其指向的对象上,则不能通过该指针修改其指向的对象;绑定常量的引用必须是指向常量的引用,指向常量的引用绑定的未必是常量。

    修饰引用:不能够通过该引用修改其绑定的对象。绑定常量的引用必须是指向常量的引用,指向常量的引用绑定的未必是常量。

    修饰函数:修饰隐式的this指针,将this指针设置为指向常量的指针,所以不能在函数体内修改数据成员。

    4.new/delete和malloc/free的区别

    new/delete最终调用malloc/free来申请和释放内存。

    c++封装了new和delete完成为对象分配内存,调用构造函数,调用析构函数,释放内存工作。

    使用上比malloc和free更加方便,不用指定大小;引入异常bad_alloc。

    new和delete通过调用operator new和operator delete来分配和释放内存, 而这两个函数可以重载,为程序员自己实现内存管理提供了方便。

    5 struct和class的区别

    在功能上基本没有什么区别,class能做到事情struct基本能做。struct可以有成员函数,可以继承,可以有虚函数(实现多态)。

    区别在于默认的访问控制:

    6.const和define的区别

    处理阶段:const在编译运行阶段使用,define在编译预处理阶段展开

    存储方式:const需要分配内存来存储常量,而define不用分配内存

    安全性:编译器会对const做类型检查更加安全。

    作用域:默认情况下const的作用范围是文件内部,多个文件共享需要使用extend ,#define的作用范围是全局,多个文件定义define同名会报错。

    7.const和static的区别

    内存区域:

    8.const和static在类中使用的注意事项

    static成员不属于任何对象,而是被他们共享。

    静态数据成员应该在类的外部定义。

    因为没有this指针,static成员函数不能用const修饰,也不能访问非静态成员。

    9.c++内存管理

    10.内联函数

    将函数指定为内联函数(inline),调用位置上内联展开,避免函数调用的开销(堆栈维护,调整指令)。应用在规模小,流程直接,频繁调用的函数。

    将代码放在符号表里,在调用点上展开。

    内联说明只是向编译器发出一个请求,编译器可以忽略这个请求。编译器优化时,也可能将没有inline说明的函数展开成内联函数。

    11.多态和虚函数

    C++通过虚函数实现动态绑定,也就是多态。

    动态绑定是根据对象本身,而不是指针或引用的类型来确定具体调用的函数。具体实现是在对象中维护一个虚函数表指针,同个虚函数表中存储了对象调用的函数的指针。

    虚函数通过虚函数指针和虚函数表来实现动态绑定。

    编译器编译时,为每个有虚函数的类生成一个虚函数表(一个一维数组),用来存储该类的虚函数地址。

    编译器为每个对象提供一个指向虚表的指针。(在32位机器的内存上看,是其前4个字节,这也是为什么有虚函数的类型的sizeof多4个字节的原因)。

    指向虚表的指针的初始化在构造函数中进行。

    虚函数的位置,按照先后顺序排列。

    子类复制一份父类的虚函数表,替换重写的虚函数地址,新加的虚函数依此放在表尾。

    12.C++中的重载和重写的区别:

    重载:名称相同参数不同。对操作相识的函数,用相同的名字,方便程序员的理解,减轻起名字,记名字的负担。

    重写:同名同参数,虚函数,子类将父类覆盖掉(在虚函数表中覆盖掉),即使通过强制类型转化也不能访问(对指针和引用而言)。

    重定义:同名(参数可同可不同),基类中的函数被隐藏,子类对象无法直接访问。

    13.面向对象的三个特征

    继承,多态,封装。

    继承:本质是代码复制。

    多态:多态和虚函数

    封装:将数据和和对操作封装到放在一起。

    14.析构函数一般写成虚函数的原因 

    delete父类指针时,可以调用对像真正的析构函数。否则可能会出错,如子类中有指针类型,并且申请了内存,这时就会造成内存泄漏。

    15.构造函数为什么一般不定义为虚函数

    析构函数通过虚表来调用的,而指向虚表的指针是在构造函数中初始化的,这是个矛盾。

    16.构造函数或者析构函数中调用虚函数会怎样

    结果上来看和调用普通函数无异。即基类调用基类的虚函数,派生类调用派生类的虚函数。

    17.纯虚函数

    18.引用是否能实现动态绑定,为什么引用可以实现

    引用和指针的静态类型和动态类型可以不一样。

    静态类型:变量声明时的类型或表达式生成的类型。编译时已经知道。

    动态类型:变量或表达式表示的内存的对象的类型。

    19.深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)

    在有指针成员的情况下,浅拷贝只是将指针指向已存在的内存。即两个对象的指针成员指向的是同一内存区域。

    深拷贝的做法是申请一个内存复制一份,并将新对象指针指向备份区。

    安全性:浅拷贝如果修改了指针指向的内容,将对两个对象都有影响。

    20.对象复用的了解,零拷贝的了解

    对象池:对象池通过对象复用的方式来避免重复创建对象,它会事先创建一定数量的对象放到池中,当用户需要创建对象的时候,直接从对象池中获取即可,用完对象之后再放回到对象池中,以便复用。

    适用性:类的实例可重用。类的实例化过程开销较大。类的实例化的频率较高。

    零拷贝:emplace_back

    21.什么情况下会调用拷贝构造函数

    (1)用类的一个对象去初始化另一个对象时

    (2)当函数的形参是类的对象时(也就是值传递时),如果是引用传递则不会调用

    (3)当函数的返回值是类的对象或引用时

    22.结构体内存对齐方式和为什么要进行内存对齐?

    23.内存泄露的定义,如何检测与避免?

    申请的堆没有被释放,该内存不能在被利用。

    24.手写实现智能指针类

    25.调试程序的方法

    26.C++的四种强制转换(C++不是类型安全的)

    static_cast , dynamic_cast , const_cast , reinterpret_cast

    static_cast:可以实现C++中内置基本数据类型之间的相互转换。

    const_cast: 操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。

    reinterpret_cast:有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。

    dynamic_cast:1)运行时处理,类型检查;2)不能用于内置的基本数据类型的强制转换;3)转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL(指针类型,如果是应用类型,抛出bad_cast异常);4)使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过;5)

    27.遇到coredump要怎么调试

    28.调试程序的方法

    29.模板的用法与适用场景

    模板是C++泛型编程的基础。

    使用:template  //关键字+<模板参数列表>

    非类型模板参数:

    应用场景:除了参数类型不一样外,其他的内容全部一样(函数体),用模板,而不是每一个类型都写一个函数。

    特化:模板的一个独立的定义,其中一个或多个参数被指定为特定的类型。通用模板不能适应所有情况。(特殊情况特殊处理)

    30.成员初始化列表的概念,为什么用成员初始化列表会快一些

    概念:以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式,对成员进行初始化。

    效率:构造函数之前执行默认初始化。而成员初始化列表,可以立即初始化,所以更快些。

    成员是const对象和引用必须初始化。

    31.虚继承

    为了避免一个类多次集成一个基类而包含多份基类的拷贝,使用虚继承机制。(基于多重继承)

    32.函数调用过程(堆栈图)

    相关文章

      网友评论

        本文标题:C++面试题整理

        本文链接:https://www.haomeiwen.com/subject/hwyonxtx.html