万字长文超全C++面经

2024年 1月 11日 52.5k 0

本文经自动驾驶之心公众号授权转载,转载请联系出处。

1. 开始

本文目的是整理面试常见的会问到的题目, 具体细节的学习需要参考 C++ Primer / Effective C++ 系列书籍 / Inside the C++ Object Model 进行学习.

为了方便查阅, 补充了可能没有面试内容的一级标题. 这样一级标题可以和 C++ Primer 书籍保持一致.

1.1. C 和 C++ 的区别

设计思想上:

  • C++ 是面向对象的语言, C 是面向过程的语言

语法上:

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

2. 变量和基本类型

2.1. 复合类型

复合类型(compound type)是指基于其他类型定义的类型. 最常见的是引用和指针.

引用即别名: 引用(reference)为对象起了另外一个名字, 引用类型引用(refers to)另外一种类型.

  • 定义引用时, 程序把引用和它的初始值绑定在一起, 而不是将初始值拷贝给引用. 一旦初始化完成, 引用将和它的初始值对象一直绑定在一起. 因为无法令引用重新绑定到另外一个对象, 因此引用必须初始化.
  • 因为引用不是一个对象, 所以不能定义引用的引用.

指针(pointer)是指向(point to)另外一种类型的复合类型.

  • 指针无需在定义时赋初值.
  • 指针本身就是一个对象, 允许对指针赋值和拷贝, 而且在指针的生命周期内它可以先后指向几个不同的对象.

表 2.1 指针与数组的区别

2.2. const限定符

2.2.1. 作用

  • 修饰变量: 表明该变量的值不可以被改变.
  • 修饰指针: 区分指向常量的指针和常量指针.
  • 修饰引用: 用于形参, 既避免了拷贝, 又避免了函数对值的修改.
  • 修饰成员函数: 表示函数不能修改成员变量(实际上是修饰this指针)

补充:

  • 对于局部对象,常量存放在栈区;
  • 对于全局对象, 常量存放在全局/静态存储区;
  • 对于字面值常量, 常量存放在常量存储区(代码段).

2.2.2. 指向常量的指针 VS 常量指针

参考 C++ Primer 2.4.2 指针和const:

  • 指向常量的指针(pointer to const):
  • 具有只能够读取内存中数据, 却不能够修改内存中数据的属性的指针(底层 const).
  • const int * p;或者int const * p;
  • 常量指针(const pointer): 常量指针是指指针所指向的位置不能改变, 即指针本身是一个常量(顶层 const), 但是指针所指向的内容可以改变.
  • 常量指针必须在声明的同时对其初始化, 不允许先声明一个指针常量随后再对其赋值, 这和声明一般的常量是一样的.
  • int * const p = &a;

2.2.3. cosntexpr

  • 常量表达式(const expression)是指值不会改变并且在编译过程就能得到计算结果的表达式.
  • 一般来说, 如果认定变量是一个常量表达式, 那就把它声明成constexpr类型.
  • 一个constexpr指针的初始值必须是nullptr或者0, 或者是存储于某个固定地址中的对象.
  • constexpr函数是指能用于常量表达式的函数.
  • 函数的返回类型及所有的形参的类型都得是字面值类型.
  • 函数体中必须有且只有一条return语句.

2.2.4. #define VS const

3. 字符串、向量和数组

4. 表达式

4.1. 右值

C++的表达式要不然是右值(rvalue), 要不然是左值(lvalue). 这两个名词是从 C 语言继承过来的, 原本是为了帮助记忆: 左值可以位于赋值语句的左侧, 右值则不能.

当一个对象被用做右值的时候, 用的是对象的值(内容); 当对象被用做左值的时候, 用的是对象的身份(在内存中的位置).

4.2. ++i/i++

前置版本++i: 首先将运算对象加 1, 然后将改变后的对象作为求值结果.

后置版本i++: 也会将运算对象加 1, 但是求解结果是运算对象改变之前的那个值的副本.

以下摘录自 More Effective C++ Item 6:

// prefix form(++i): increment and fetch
UPInt&  UPInt::operator++()
{
    *this +=1;        // increment
    return *this;     // fetch
}
// postfix form(i++): fetch and increment
const UPInt UPInt::operator++(int)
{
    const UpInt oldValue = *this; // fetch
    ++(*this);                    // increment
    return oldValue;             // return what was fetched
}

4.3. sizeof运算符

4.3.1. 普通变量执行sizeof

sizeof运算符的结果部分地依赖于其作用的类型:

  • 对char或者类型为char的表达式执行sizeof运算, 结果得 1.
  • 对引用类型执行sizeof运算得到被引用对象所占空间的大小.
  • 对指针执行sizeof运算得到指针本身所占空间的大小.
  • 对解引用指针执行sizeof运算得到指针指向的对象所占空间的大小.
  • 对数组执行sizeof运算得到整个数组所占空间的大小, 等价于对数组中所有元素各执行一次sizeof运算并将所得结果求和.
  • 对string对象或vector对象执行sizeof运算只返回该类型固定部分的大小.

4.3.2. 类执行sizeof

class A {};
class B { B(); ~B() {} };
class C { C(); virtual ~C() {} };
class D { D(); ~D() {} int d; };
class E { E(); ~E() {} static int e; };
int main(int argc, char* argv[]) {
std::cout

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论