史上最全的C++面试宝典(合集)

参考:https://www.runoob.com/cplusplus/cpp-tutorial.html

本教程旨在提取最精炼、实用的C++面试知识点,供读者快速学习及本人查阅复习所用。

目录

第一章  C++基本语法

1.1  C++程序结构

1.2  命名空间

1.3  预处理器

1.4  相关面试题

第二章  C++数据操作

2.1  数据类型

2.2  变量

2.3  常量

2.4  类型限定符

2.5  存储类

2.6  运算符

2.7  相关面试题

第三章  指针和引用

3.1  指针

3.2  引用

3.3  相关面试题

第四章  函数——C++的编程模块

4.1  函数的定义与声明

4.2  内联函数

4.3  重载

4.4  模板

4.5  相关面试题

第五章  结构体、类与对象

5.1  结构体

5.2  类和对象

5.3  数据抽象与封装

5.4  继承

5.5  多态

5.6  相关面试题

第六章  动态内存

6.1  new和delete运算符

6.2  动态内存分配

6.3  相关面试题

第七章  C++ STL(标准模板库)

7.1  容器

7.2  相关面试题

第八章  异常处理

8.1  抛出异常

8.2  捕获异常

8.3  C++标准的异常

8.4  定义新的异常

第九章  多线程

9.1  基本概念

9.2  C++线程管理

9.3  线程的同步与互斥

9.4  C++中的几种锁

9.5  C++中的原子操作

9.6  相关面试题


第一章  C++基本语法

C++ 程序可以定义为对象的集合,这些对象通过调用彼此的方法进行交互。

  • 对象 - 对象具有状态和行为。例如:一只狗的状态 - 颜色、名称、品种,行为 - 摇动、叫唤、吃。
  • 类 - 类可以定义为描述对象行为/状态的模板,对象是类的实例。
  • 方法 - 从基本上说,一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据等动作。
  • 即时变量 - 每个对象都有其独特的即时变量。

1.1  C++程序结构

下面给出一段基础的C++程序:

#include <iostream>
using namespace std;
// main() 是程序开始执行的地方
int main()
{
   cout << "Hello World" << endl; // 输出 Hello World
   return 0;
}

这段程序主要结构如下:

  • C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 <iostream>
  • using namespace std; 告诉编译器使用 std 命名空间。
  • int main() 是主函数,程序从这里开始执行。

1.2  命名空间

  • 命名空间这个概念可作为附加信息来区分不同库中相同名称的函数、类、变量等。
  • 使用了命名空间即定义了上下文,本质上,命名空间就是定义了一个范围。

1.2.1  定义命名空间

下面通过一个示例来展示如何定义命名空间并使用命名空间中的函数等。

#include <iostream>
using namespace std;
 
// 第一个命名空间
namespace first_space{
   void func(){
      cout << "Inside first_space" << endl;
   }
}
// 第二个命名空间
namespace second_space{
   void func(){
      cout << "Inside second_space" << endl;
   }
}
int main ()
{
   // 调用第一个命名空间中的函数
   first_space::func();
   // 调用第二个命名空间中的函数
   second_space::func(); 
   return 0;
}

1.2.2  using指令

可以使用 using namespace xxxx指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。

1.3  预处理器

预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预处理指令之前。预处理指令不是 C++ 语句,所以它们不会以分号(;)结尾。

1.3.1  #define预处理

#define 预处理指令用于创建符号常量。该符号常量通常称为宏,指令的一般形式是:

#define macro-name replacement-text 
//例如
#define PI 3.14159

可以使用 #define 来定义一个带有参数的参数宏,如下所示:

#include <iostream>
using namespace std;
 
#define MIN(a,b) (a<b ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
   cout <<"较小的值为:" << MIN(i, j) << endl;
 
    return 0;
}

1.3.2  条件编译

有几个指令可以用来有选择地对部分程序源代码进行编译。这个过程被称为条件编译。

条件预处理器的结构与 if 选择结构很像。请看下面这段预处理器的代码:

#ifndef NULL
   #define NULL 0
#endif

例如,要实现只在调试时进行编译,可以使用一个宏来实现,如下所示:

#ifdef DEBUG
   cerr <<"Variable x = " << x << endl;
#endif

使用 #if 0 语句可以注释掉程序的一部分,如下所示:

#if 0
   不进行编译的代码
#endif

下面给出一个示例:

#include <iostream>
using namespace std;
#define DEBUG
 
#define MIN(a,b) (((a)<(b)) ? a : b)
 
int main ()
{
   int i, j;
   i = 100;
   j = 30;
#ifdef DEBUG
   cerr <<"Trace: Inside main function" << endl;
#endif
 
#if 0
   /* 这是注释部分 */
   cout << MKSTR(HELLO C++) << endl;
#endif
 
   cout <<"The minimum is " << MIN(i, j) << endl;
 
#ifdef DEBUG
   cerr <<"Trace: Coming out of main function" << endl;
#endif
    return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Trace: Inside main function
The minimum is 30
Trace: Coming out of main function

1.4  相关面试题

Q:C++和C的区别

A:设计思想上:

  • C++是面向对象的语言,而C是面向过程的结构化编程语言

语法上:

  • C++具有封装、继承和多态三种特性
  • C++相比C,增加多许多类型安全的功能,比如强制类型转换
  • C++支持范式编程,比如模板类、函数模板等

Q:为什么C++支持函数重载而C语言不支持呢

A:在链接阶段,C语言是通过函数本名去寻找函数的实体的,所以当两个函数同名时是无法识别的;而C++会将函数名和函数带的参数转换成编译特征和固有特征,这时候编译器就可以分辨出两个同名不同参的函数。

Q:include头文件双引号””和尖括号<>的区别

A:编译器预处理阶段查找头文件的路径不一样:

  • 对于使用双引号包含的头文件,编译器从用户的工作路径开始搜索
  • 对于使用尖括号包含的头文件,编译器从标准库路径开始搜索

Q:头文件的作用是什么?

A:

  1. 通过头文件来调用库功能。
  2. 头文件能加强类型安全检查。

Q:在头文件中进行类的声明,在对应的实现文件中进行类的定义有什么意义?

A:这样可以提高编译效率,因为分开的话,这个类只需要编译一次生成对应的目标文件,以后在其他地方用到这个类时,编译器查找到了头文件和目标文件,就不会再次编译这个类,从而大大提高了效率。

Q:C++源文件从文本到可执行文件经历的过程

A:对于C++源文件,从文本到可执行文件一般需要四个过程:

  1. 预编译阶段:对源代码文件中文件包含关系(头文件)、预编译语句(宏定义)进行分析和替换,生成预编译文件
  2. 编译阶段:将经过预处理后的预编译文件转换成特定汇编代码,生成汇编文件
  3. 汇编阶段:将编译阶段生成的汇编文件转化成机器码,生成可重定位目标文件
  4. 链接阶段:将多个目标文件及所需要的库链接成最终的可执行目标文件

Q:静态链接与动态链接

A:静态链接是在编译期间完成的。

  • 静态链接浪费空间 ,这是由于多进程情况下,每个进程都要保存静态链接函数的副本。
  • 更新困难 ,当链接的众多目标文件中有一个改变后,整个程序都要重新链接才能使用新的版本。
  • 静态链接运行效率高。

动态链接的进行则是在程序执行时链接。

  • ​动态链接当系统多次使用同一个目标文件时,只需要加载一次即可,节省内存空间。
  • 程序升级变得容易,当升级某个共享模块时,只需要简单的将旧目标文件替换掉,程序下次运行时,新版目标文件会被自动装载到内存并链接起来,即完成升级。

Q:C++11有哪些新特性

A:

  • auto关键字:编译器可以根据初始值自动推导出类型,但是不能用于函数传参以及数组类型的推导;
  • nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。
  • 智能指针:C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题。
  • 初始化列表:使用初始化列表来对类进行初始化
  • 右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率
  • atomic原子操作用于多线程资源互斥操作
  • 新增STL容器array以及tuple

Q:assert()是什么

A:断言是宏,而非函数。assert 宏的原型定义在 <assert.h>(C)、<cassert>(C++)中,其作用是如果它的条件返回错误,则终止程序执行。可以通过定义 NDEBUG 来关闭 assert,但是需要在源代码的开头,include <assert.h> 之前。

#define NDEBUG          // 加上这行,则 assert 不可用
#include <assert.h>
assert( p != NULL );    // assert 不可用

Q:C++是不是类型安全的?

A:不是,因为两个不同类型的指针之间可以强制转换(用reinterpret cast)。

Q:系统会自动打开和关闭的3个标准的文件是?

A:

  1. 标准输入----键盘---stdin
  2. 标准输出----显示器---stdout
  3. 标准出错输出----显示器---stder

 

第二章  C++数据操作

2.1  数据类型

2.1.1  基本类型

C++有7种基本的数据类型:

基本数据类型

可以使用signed,unsigned,short,long去修饰这些基本类型:

类型及大小

2.1.2  typedef

可以使用 typedef 为一个已有的类型取一个新的名字。例如:

//typedef type newname; 
typedef int feet;
feet distance

typedef struct Student {
    int age;
} S;
S student;

2.2  变量

2.2.1  变量定义

//type variable_name = value;
extern int d = 3, f = 5;    // d 和 f 的声明 
int d = 3, f = 5;           // 定义并初始化 d 和 f
byte z = 22;                // 定义并初始化 z
char x = 'x';               // 变量 x 的值为 'x'

2.2.2  变量声明
可以使用extern关键字在任意地方声明一个变量。

// 变量声明
extern int a, b;
extern float f;
  
int main ()
{
  // 变量定义
  int a, b;
  float f;

  return 0;
}

同样的,函数声明是,提供一个函数名即可,而函数的实际定义则可以在任何地方进行。

// 函数声明
int func();
 
int main()
{
    // 函数调用
    int i = func();
}
 
// 函数定义
int func()
{
    return 0;
}

2.2.3  变量作用域

  1. 在函数或一个代码块内部声明的变量,称为局部变量。
  2. 在函数参数的定义中声明的变量,称为形式参数。
  3. 在所有函数外部声明的变量,称为全局变量。

注:当局部变量被定义时,系统不会对其初始化,您必须自行对其初始化。定义全局变量时,系统会自动初始化为下列值:

变量初始化

2.3  常量

常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。

2.3.1  define预处理器

下面是使用 #define 预处理器定义常量的形式:

#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'

2.3.2  const关键字

可以使用 const 前缀声明指定类型的常量,const类型的对象在程序执行期间不能被修改。如下所示:

const int  LENGTH = 10;
const int  WIDTH  = 5;
const char NEWLINE = '\n';

2.4  类型限定符

2.4.1  volatile

volatile 用来修饰变量,表明某个变量的值可能会随时被外部改变,因此使用 volatile 告诉编译器不应对这样的对象进行优化(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值;而被volatile修饰的变量,它不能被缓存到寄存器,每次访问需要到内存中重新读取)。

volatile int n = 10;

2.4.2  restrict

由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。

2.5  存储类

存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期。

2.5.1  auto存储类

auto 关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符。

2.5.2  static存储类

static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。

  • 使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
  • 当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
  • 在 C++ 中,当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。

2.5.3  extern存储类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。通常用于当有两个或多个文件共享相同的全局变量或函数的时候。

2.6  运算符

算数运算符​​​

 

 

关系运算符

 

逻辑运算符

 

位运算符

 

赋值运算符

 

杂项运算符

 

运算符优先级

2.7  相关面试题

Q:const的作用

A:

  1. 修饰变量,说明该变量不可以被修改
  2. 修饰指针,即常量指针和指针常量
  3. 常量引用,经常用于形参类型,既避免了拷贝,又避免了函数对值的修改
  4. 修饰类的成员函数,说明该成员函数内不能修改成员变量
// 类
class A
{
private:
    const int a;                // 常对象成员,只能在初始化列表赋值
public:
    // 构造函数
    A() : a(0) { };
    A(int x) : a(x) { };   
  • 82
    点赞
  • 593
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值