共计 5827 个字符,预计需要花费 15 分钟才能阅读完成。
C++
作为一门重要的编程语言,其在面试中经常是热门的考查对象。本文将会介绍一些常见的 C++
面试题,帮忙 C++
面试者防止很多不必要的困惑和蛊惑。每个问题都有绝对应的答案,以便各位同学疾速查阅。
C++ 和 C 的区别是什么?
C++
是 C
的超集,也就是说,C++
包含了 C
的所有根底个性,并且还减少了一些新的个性。上面列举一些 C
和C++
之间的次要区别:
- 面向对象编程
C++
是一种面向对象的编程语言,而 C
不是。因而,C++
反对类、继承、封装、多态等一系列面向对象的概念和个性,这些能力使 C++
更加灵便和弱小。
- 规范库
C++
规范库比 C
规范库更加欠缺和弱小。C++
规范库包含了很多容器类,如 vector
、map
、set
等,以及输入输出流、字符串解决等罕用性能。这些库函数能够在许多状况下进步开发效率。
- 命名空间
C++
引入了命名空间的概念,能够防止函数命名雷同的抵触。应用命名空间能够将代码依照逻辑分组,并更好地组织代码。
- 异样解决
C++
反对异样解决机制,这个机制能够加强程序的容错性和可靠性。当程序产生异样时,能够抛出异样并在可控范畴内进行解决,防止程序解体。而 C
不反对异样解决机制。
- 运算符重载
C++
容许对运算符进行重载,能够使得运算符在解决特定类型的数据时更具备描述性。而 C
不反对运算符重载。什么是指针?
指针是 C++
中的一种数据类型,指针变量存储了一个内存地址,该地址指向某个变量或者对象。指针能够用来拜访和批改内存中的数据,同时也能够通过指针来传递参数和返回值。对于 C++
程序员来说,精通指针的应用是十分重要的。
重写和重载的区别
重写指的是在派生类中从新定义基类的虚函数的行为。当基类中的某个虚函数在派生类中被从新定义时,如果派生类对象调用该函数,则会笼罩掉基类中的实现,执行派生类中的实现代码。在进行对象的多态性转换时,重写十分重要。
重载则指的是在同一个作用域内申明几个同名然而参数列表不同的函数。通过函数名雷同但参数类型、个数或程序的不同,能够让多个函数具备不同的行为。例如,C++
中能够重载函数来解决不同类型的数据,如整数、浮点数等。在应用函数时,依据传递给函数的参数类型和个数来主动抉择对应的函数进行调用。
因而,重写和重载的次要区别在于,重写是通过派生类从新定义基类虚函数的行为,以实现运行时多态性;而重载是在同一作用域内申明几个雷同名称的函数,以实现编译时多态性。
讲讲面向对象
面向对象编程有 3 大个性:
- 封装:封装是指将对象的属性和办法绑定在一起,造成一个独立的、关闭的单元。内部只能通过对象提供的公共接口来拜访或操作对象的外部状态,而无奈间接拜访或批改对象的数据。这样能够保障对象的外部状态不受内部烦扰,从而进步了程序的安全性和可靠性,简化了代码的调用形式。
- 继承:通过继承机制,一个类能够从另一个类中继承某些属性和办法,并在此基础上增加新的属性和办法,从而防止了反复编写代码的冗余,进步了代码的可重用性和可维护性。
- 多态:多态是指同一个音讯能够被不同的对象解释执行,即不同的对象对同一音讯作出不同的响应。具体来说,多态能够通过虚函数和模板等机制实现。通过多态,能够使代码更加灵便、可扩大,同时也可能使程序更易读懂和保护。
这三个个性是面向对象编程的外围,它们相互配合,独特组成了一个残缺的面向对象编程体系,可能无效地进步程序的可靠性、可重用性、可扩展性等方面。
什么是援用?
援用也是 C++
中的一种数据类型,它提供了一种简洁而高效的形式来操作变量和对象,而不须要拷贝它们自身。援用被视为原变量的一个别名,其操作相似于指针,然而援用不能被赋值为NULL
,也不能进行指针运算。
C/C++ 援用和指针的区别?
指针是一个实体,须要分配内存空间;援用只是变量的别名,不须要分配内存空间。援用在定义的时候必须进行初始化,并且不可能扭转;指针在定义的时候不肯定要初始化,并且指向的空间可变。有多级指针,然而没有多级援用,只能有一级援用。指针和援用的自增运算后果不一样。
内联函数和一般函数有什么区别?
内联函数和一般函数的区别在于是否进行了“内联优化”。内联函数是一种非凡的函数,编译器会在编译时将其整个函数体插入到调用该函数的中央,从而节俭了函数调用的开销。一般函数则须要在调用时进行函数栈的压栈和出栈操作,这样会带来额定的工夫和空间开销。因而,对于简略的函数或者频繁被调用的函数,咱们能够思考应用内联函数来进步程序的性能。
常量指针和指针常量?
常量指针是指针指向的地址不能扭转,然而能够通过指针批改地址对应的值。而指针常量则是指针指向的地址能够扭转,然而不能通过指针批改地址对应的值。
在 C
语言中,常量指针的定义形式为const int* ptr
,示意指向 int 类型的常量指针,指针所指向的地址不能扭转,然而能够通过指针批改地址对应的值。
而指针常量的定义形式为int* const ptr
,示意指向 int 类型的指针常量,指针所指向的地址能够扭转,然而不能通过指针批改地址对应的值。
如果想要定义既不能批改地址,也不能批改地址对应的值的指针,能够应用const int* const ptr
。
常量指针和指针常量的区别在于指针所指向的内容可不可变,须要依据具体情况而定。
P.S. 感兴趣的同学能够看我之前帖子,有具体介绍
如何防止野指针?
野指针是指指向曾经被开释或者有效的内存空间的指针,这是 C++
中常见的一个程序谬误。当咱们拜访野指针时,程序会呈现不可预期的行为,甚至解体。
为了防止野指针,咱们能够采取以下措施:
- 在指针应用前初始化
在定义一个指针变量的时候,咱们应该立刻将其初始化为一个无效的地址。如果不能确定指针的初始值,能够将其初始化为 nullptr
或 0,防止野指针的产生。
int* p = nullptr; // 初始化为空指针
- 在指针应用后及时置空
当指针变量不再应用时,咱们应该将其置为空指针,避免误用。这样能够无效地防止产生野指针。
int* p = new int;
*p = 10;
delete p;
p = nullptr; // 置空指针,防止野指针产生
- 不要反复开释曾经开释的内存
在开释指针所指向的内存空间之后,咱们应该将该指针赋值为 NULL
或 nullptr
,以避免该指针被误用。
int* p = new int;
delete p;
p = nullptr; // 置空指针,防止野指针产生
// 以下代码会产生谬误,因为指针 p 曾经被开释
delete p;
- 防止应用悬空指针
当一个指针变量超出了其所在作用域或者被删除时,它就成为了“悬空指针”,这是一种常见的野指针。咱们应该防止应用悬空指针,同时要留神存储指针所指向的对象生命周期的问题。
总之,防止野指针是 C++
中一个很重要的问题,能够通过初始化、及时置空、防止开释曾经开释的内存、防止应用悬空指针等措施来防止产生野指针,从而保障程序的正确性和稳定性。
C++ 多态?
C++
多态是指在继承关系中,子类能够重写父类的虚函数,从而使得一个指向子类对象的指针可能调用子类的函数而不是父类的函数。其底层原理波及到虚函数表、虚指针等概念。虚函数表是一个存储类的虚函数地址的数据结构,每个蕴含虚函数的类都有本人的虚函数表。
虚指针是一个指向虚函数表的指针,每个含有虚函数的对象都有一个虚指针。虚指针的设置是由编译器来实现的,当一个类中含有虚函数时,编译器就会在类中减少一个虚指针来指向虚函数表,每个对象都有一个虚指针,指向它所属的类的虚函数表。
通过虚函数表和虚指针,使得程序可能在运行时依据对象的理论类型来确定调用哪个函数。
什么是虚函数?
虚函数是 C++
中的一种非凡函数,它能够实现多态性。当一个类中蕴含至多一个虚函数时,它就被称为虚类或抽象类。这些虚函数由子类重写,使得它们能够依据须要对基类的行为进行扩大和批改。通过应用虚函数能够实现动静绑定和运行时多态。
以上是一些常见的 C++
面试题及其答案,当然可能还有其余的问题波及到了更深刻的知识点。无论何种状况,咱们应该放弃虚心、认真和激情,去面对每一个机会,以便在面试中显示出本人的技能和能力。
基类的析构函数为何要申明为虚函数?
C++ 基类的析构函数申明为虚函数是为了确保在通过基类的指针或援用删除派生类对象时,能够正确地开释派生类对象所占用的内存。如果基类的析构函数不是虚函数,则在这种状况下只会调用基类的析构函数,而不会调用派生类的析构函数,从而可能导致内存透露和未定义行为。因而,将基类的析构函数申明为虚函数是一种良好的编程实际,能够确保在多态状况下正确地开释内存。
数组和指针的区别?
它们尽管在某些方面类似,然而有很多区别。
- 内存用法
数组名是一个指向数组首元素的常量指针,它存储的是数组首元素的地址。而指针是一个变量,它存储的是某个对象的地址。
- 操作的灵活性
数组名是一个常量指针,不能批改,而指针能够被从新赋值,指向其余对象。因而应用指针比应用数组名更加灵便,能够在运行时动静确定指向的对象。
- 大小
数组名的大小等于数组中元素的总数乘以每个元素的大小,而指针的大小是与零碎架构无关的,通常是一个字长(word length
)。
- 函数参数传递
如果将数组名作为函数参数传递,实际上传递的是一个指向数组首元素的指针。而如果将指针作为函数参数传递,能够不便地批改指针所指向的对象。
- 数组解援用
能够通过数组下标拜访数组元素,也能够应用指针进行拜访,然而须要留神的是,应用指针拜访数组元素须要先将指针解援用,即应用 *
运算符。例如:*p
示意 p
指向的对象。
C/C++ 内存有哪几种类型?
内存分为堆、栈、程序代码区、全局 / 动态存储区和常量存储区。C++ 中还有自在存储区(new
)。
P.S. 感兴趣的同学能够看我之前帖子,有具体介绍
C++ 堆和栈的区别?
堆寄存动态分配的对象,生存期由程序控制;栈用来保留定义在函数内的非 static
对象,仅在其定义的程序块运行时才存在;动态内存用来保留 static
对象,类 static
数据成员以及定义在任何函数内部的变量,static
对象在应用之前调配,程序完结时销毁;栈和动态内存的对象由编译器主动创立和销毁。
程序编译的过程是怎么的?
程序编译的过程通过预处理、编译、汇编和链接四个过程。
之前帖子有具体介绍
计算机外部如何存储正数和浮点数?
正数通过一个标记位和补码来示意,浮点数采纳单精度类型(float
)和双精度类型(double
)来存储,float
数据占用 32bit
,double
数据占用64bit
。
C++ extern 作用?
在 C++
中,extern
关键字用于申明一个曾经在别处定义的变量、函数或类的援用,从而容许在一个文件中应用在其余文件中定义的全局变量、函数或类。
比方,如果在一个 .cpp
文件中定义了一个全局变量 int globalVar = 10;
,那么在另一个.cpp
文件中能够通过应用 extern int globalVar;
来援用这个全局变量,从而能够应用它的值。
此外,extern
关键字还能够用于在多个文件中共享一个函数或类的定义。例如,如果有一个类的定义在一个.h 文件中,那么在多个 .cpp
文件中能够应用 extern
关键字来申明这个类的援用,从而能够在这些文件中应用这个类的成员函数。
C++ 函数调用的过程?
C++
函数调用是编程中常见的一个操作,其过程能够分为以下几个阶段:
- 函数调用前的筹备工作
在函数调用之前,须要进行一些筹备工作。首先,须要将函数的参数压入栈中,以向函数传递参数。其次,须要保留以后函数的返回地址,以便在函数调用完结后返回到正确的地位。
- 进入函数调用
调用函数时,程序会跳转到函数代码的入口点。此时,程序会为函数创立一个新的栈帧,用于存储函数的局部变量、返回值等信息。栈帧蕴含了多个局部,例如函数参数、局部变量、返回地址等等。函数参数通过栈传递,在栈的顶部。局部变量则被调配在栈帧的底部。返回地址保留在栈帧中,这样函数调用完结后程序能力正确返回。
- 函数外部解决
函数外部会执行具体的操作,包含参数的读取、局部变量的申明和应用、逻辑计算、循环或者条件语句等等。函数将依据其实现过程来计算参数并进行其余操作,而后返回一个后果,该后果通常被保留在寄存器中。
- 函数返回
当函数执行结束时,须要将返回值存储,并复原主函数的栈帧及解决状态。函数返回时,会跳转回调用它的函数的地位。此时,程序会弹出函数栈帧,将返回值传递给调用者,并复原调用者的寄存器和栈。
左值和右值?
左值是能够寻址的,有名字的,非长期的变量或表达式;右值是不能寻址的,没有名字的,长期的,生命周期在某个表达式之内的变量或表达式。
P.S. 感兴趣的同学能够看我之前帖子,有具体介绍
内存透露以及防止和缩小这类谬误的办法?
内存透露是指用动态存储分配函数动静开拓的空间,在应用结束后未开释,导致始终占据该内存单元的状况。防止和缩小内存透露和指针越界的谬误,能够留神指针的长度、malloc
时须要确定在哪里 free
、对指针赋值时留神被赋值指针须要不须要开释、动静分配内存的指针最好不要再次赋值、在C++
中优先思考应用智能指针等。
malloc 和 new 的区别
malloc
和 new
都是用于动静分配内存的函数,但它们在应用办法和成果上有一些区别:
- 调用形式不同:
malloc
是C
语言规范库中的函数,须要以函数调用模式调用,并且须要指定要调配的内存大小。而new
是C++
关键字,在应用时间接在类型前面增加括号即可,无需显式地指定内存大小。 - 内存调配形式不同:
malloc
只负责分配内存空间,并返回该内存空间的起始地址,但不会进行初始化。而new
除了分配内存空间外,还会主动调用构造函数对对象进行初始化。 - 返回值类型不同:
malloc
返回void
类型的指针,须要进行强制类型转换,才可能应用;而new
返回一个指向已分配内存空间的指针,且不须要进行强制类型转换。 - 内存调配失败时的解决形式不同:当内存调配失败时,
malloc
会返回NULL
,并须要手动开释曾经调配的内存空间;而new
会抛出std::badalloc
异样,程序能够通过异样捕捉机制来解决。
delete 和 free 区别
delete
和 free
都能够用于开释动态分配的内存,然而它们之间有以下几点区别:
delete
是C++
中的运算符,而free
是C
语言中的函数。delete
会主动调用对象的析构函数来清理资源;而free
只是简略地开释指针所指向的内存块。delete
必须要用于new
动态分配的内存;而free
必须要用于malloc
动态分配的内存。
因而,在 C++
中应该应用 delete
来开释内存,而不是应用free
。