C++面试——基础篇

1、C和C++的区别

        1)编程范式(c:面向过程 c++: 面向对象)

        2) 动态内存分配(c: malloc/free c++:new/delete)

        3)c++支持函数重载

        4)c++支持模板

        5)c++除了指针还支持引用(引用的本质是常指针)

        可以回答的内容很多,以上作为参考,还有其他不同地方可继续总结!

2、C++文件编译与执行的四个阶段

        1)预处理:根据文件中的预处理指令来修改源文件的内容

        2)编译:编译成汇编代码        

        3)汇编:把汇编代码翻译成目标机器指令

        4)链接:链接目标代码生成可执行程序

3、 定义和声明的区别

声明是告诉编译器变量的类型和名字,不会为变量分配空间

定义需要分配空间,同一个变量可以被声明多次,但是只能被定义一次

4、C++的内存管理

在C++中,内存被分成五个区:栈、堆、自由存储区、静态存储区、常量区

栈:存放函数的参数和局部变量,编译器自动分配和释放

堆:new关键字动态分配的内存,由程序员手动进行释放,否则程序结束后,由操作系统自动进行回收

自由存储区:由malloc分配的内存,和堆十分相似,由对应的free进行释放

全局/静态存储区:存放全局变量和静态变量

常量区:存放常量,不允许被修改

5、extern“C”作用

extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。也就是C和C++代码的编译逻辑是不一样的,并且C中的全局变量也需要被其他引用的文件识别。

6、 static 的作用域

 某一个文件中定义的静态的变量,则它的作用域是整个文件。与之相对的的是extern!

在.h文件中定义了一个静态的全局变量x,不同文件为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的,只在该cpp文件共享该变量。所以一般定义static全局变量时,都把它放在cpp文件中而不是头文件,从而避免多个源文件共享,从而造成不必要的信息污染。

7、enum枚举类型和#define宏定义的区别

  • 宏定义没有类型检查和安全检查,所以会导致边际效应,出现不可预知的错误;enum在编译阶段进行类型检查,但是只能进行整型的定义
  • 宏定义仅仅是替换和展开,并不进行内存的分配;enum常量存储在内存数据段的静态存储区
  • define是在预处理阶段对所定义的常量进行替换展开;enum是程序运行时起作用
  • 枚举常量具有类型,但宏没有类型

8、栈溢出的原因以及解决方法

1)函数调用层次过深,每调用一次,函数的参数、局部变量等信息就压一次栈

2)局部变量体积太大。

解决办法大致说来也有两种:

1)增加栈内存的数目;增加栈内存方法如下,在vc6种依次选择Project->Setting->Link,在Category中选择output,在Reserve中输入16进制的栈内存大小如:0x10000000

2)使用堆内存;具体实现由很多种方法可以直接把数组定义改成指针,然后动态申请内存;也可以把局部变量变成全局变量,一个偷懒的办法是直接在定义前边加个static,呵呵,直接变成静态变量(实质就是全局变量)

9、 C++中const的作用以及和宏的区别

        const修饰的内容不可改变, 定义常量只是一种使用方式,还有const数据成员,const参数, const返回值, const成员函数等, 被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

        const相对#define可以做类型校验,并且分配内存。

10、 既然C++中有更好的const为什么还要使用宏

        宏的作用发生在预编译,const是再编译阶段,所以const无法代替宏作为卫哨来防止文件的重复包含。

 11、new/delete 与 malloc/free的区别?

 malloc与free是C语言的标准库函数, new/delete是C++的运算符, 他们都可以用来申请和释放内存, malloc和free不在编译器控制权限之内, 无法调用构造函数和析构函数;而new/delete是由C++编译器控制的,可以在分配内存之外调用构造函数和析构函数。

 12、RTTI

typeid 和 dynamic_cast

具体原理可以参考:C++类型预断——RTTI_master-计算机科学专栏-CSDN博客

13、 四种类型转换

(1)static_cast:用于良性转换,一般不会导致意外发生,风险很低。常用于基本类型转换到 void,转换父类指针到子类不安全 。

(2)const_cast:一般用于去掉const属性以及volatile,但是如果原来他就是常量去掉之后千万不要修改;比如你手里有一个常量指针引用,但是函数接口是非常量指针,可能需要转换一下;成员函数声明为const,你想用this去执行一个函数,也需要用const_cast.

(3)dynamic_cast:用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。

(4)reinterpret_cast:非常简单粗暴,所以风险很高,一般用于跨类型的转换,如int到void*,用于序列化网络包数据等。

 14、STL由什么组成

        由容器,迭代器,仿函数,算法,分配器,适配器构成。分配器给容器分配存储空间,算法通过迭代器获取容器中的内容,仿函数可以协助算法完成各种操作,配置器用来套接适配仿函数。

15、 什么是内存泄漏?面对内存泄漏和指针越界,你有哪些方法?

动态分配内存所开辟的空间,在使用完毕后未释放,导致一直占据该内存,即为内存泄漏。

避免内存泄漏方法:

  1.  谁开辟谁释放        
  2.  使用智能指针         
  3.  指针指向新地址时参考规则1
  4.  new和delete、new[]和delete[]要对应

 16、阐述C++的多态

多态是指一个接口多种实现,这是面向对象编程的核心,多态分为以下两种:

静态多态:也就是编译时多态,主要实现方式为重载模板

动态多态:也就是运行时多态,主要实现方式为虚函数 + 继承

17、new与new[] delete与delete[]的区别 

请参考 :深入理解new[]和delete[]_master-计算机科学专栏-CSDN博客

18、动态多态的实现原理

动态多态的实现是借助虚函数表来实现的,具体实现还要看一下C++的内存模型和C++的虚函数表的实现。(这里就不做过多讲解,如果不懂的,可以回看老师的课程视频

19、inline函数能否是virtual函数

        不可以,inline只是一个申请,最终由编译器决定内联还是不内联。如果inline函数被声明为virtual函数,编译器此时不会认为这是一个内联函数。为什么?因为inline是发生在编译阶段,而virtual是运行阶段的!

        总之,要virtual就不要inline,要inline就不要virtual!

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

        可以。因为引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指的对象的实际类型所定义的。

        换句话说,引用的本质是常量指针,指针指向的对象当然可以在运行阶段来实现动态调用。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chls

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值