C++秋招必知必会(1-20)

参考引用

1. C++ 面向对象三大特性

C++ 面向对象的三大特性为:封装、继承和多态

  • 封装
    • 在设计类时,属性和行为写在一起,表现事物
    • 类在设计时,可以把属性和行为放在不同的权限下加以控制
  • 继承
    • 让某种类型对象获得另一个类型对象的属性和方法,它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展
    • 有些类与类之间存在特殊的关系,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性,这时就可以考虑利用继承的技术,减少重复代码
    • 继承中先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

    继承与派生区别

    • 1、继承是指一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的属性和行为。派生是指通过继承,子类可以获得父类的属性和方法,并且可以在此基础上进行扩展或修改
    • 2、继承是实现代码重用和建立类之间关系的重要方式,可以减少重复代码的编写,提高代码的可维护性和可扩展性
    • 3、派生类可以重写(override)父类的方法,以实现定制化的行为;也可以通过新增方法或属性来扩展父类的功能
  • 多态
    • 定义:同一操作作用于不同的对象,产生不同的执行结果
    • 实现:通过虚函数实现,用 virtual 声明的成员函数就是虚函数,调用虚成员函数时,会根据调用类型对象的实际类型执行不同的操作
    • 实现多态的方式
      • 覆盖(override):派生类覆盖基类用 virtual 声明的成员函数,函数名、参数类型和返回值均相同
      • 重载(overload):函数名相同,参数类型或顺序不同的函数构成重载
      • 隐藏(overwrite):派生类的函数屏蔽了与其同名的基类函数
    • 多态的类型
      • 静态多态:函数重载和运算符重载属于静态多态,复用函数名,地址早绑定(编译阶段确定函数地址)
      • 动态多态:派生类和虚函数实现运行时多态,地址晚绑定(运行阶段确定函数地址)

2. main 执行前和执行后的内容

  • main 函数执行之前(主要是初始化系统相关资源)

    • 设置栈指针
    • 初始化静态(static)变量和全局(global)变量
    • 将未初始化部分的全局变量赋初值:数值型 short,int,long 等为 0,bool 为 FALSE,指针为 NULL 等
    • 将 main 函数的参数 argc、argv 等传递给 main 函数,然后才真正运行 main 函数
  • main函数执行之后

    • 全局对象的析构函数会在 main 函数之后执行
    • 可以用 atexit 注册一个函数,它会在 main 之后执行

3. 结构体内存对齐问题

  • 结构体内成员按照声明顺序存储,第一个成员地址和整个结构体地址相同
  • 未特殊说明时,按结构体中 size 最大的成员对齐(若有 double 成员,按 8 字节对齐)

4. 指针和引用的区别

  • 指针是一个变量(存储的是一个地址),引用和原变量实质上是同一个东西(是变量的别名
  • 指针可以有多级,引用只有一级
    • 指针本身存储的是地址,而地址也可以是另一个指针的地址,这样就形成了多级指针
    • 引用本质上是某个变量的别名,它在声明时就要初始化,并且在整个生命周期中只能绑定到同一变量,无法更改引用的目标,因此引用不能形成多级引用的结构
  • 指针可以为空,引用不能为 NULL 且在定义时必须初始化
  • 指针在初始化后可以改变指向,而引用在初始化后不可再改变
  • sizeof 指针得到的是本指针的大小,sizeof 引用得到的是引用所指向变量的大小
  • 当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以

5. 在传递函数参数时,使用指针/引用的时机

  • 需要返回函数内局部变量的内存时用指针
    • 使用指针传参需要开辟内存,用完要记得释放指针,不然会内存泄漏
    • 而返回局部变量的引用是没有意义的
  • 对栈空间大小比较敏感(比如递归)时用引用
    • 使用引用传递不需要创建临时变量,开销要更小
  • 类对象作为参数传递时用引用
    • 这是 C++ 类对象传递的标准方式

6. 堆和栈的区别

堆和栈在不同场景下的含义

  • 程序内存布局场景下,堆与栈表示两种内存管理方式
  • 数据结构场景下,堆与栈表示两种常用的数据结构
  • 栈就像去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,好处是快捷,但是自由度小
  • 堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大
  • 栈与堆哪个更快?见下图:分配效率

在这里插入图片描述

7. 栈和队列(数据结构)的区别

  • 规则不同
    • 队列:先进先出
    • 栈:先进后出
  • 对插入和删除的限定不同
    • 队列:只能在表的一端进行插入,并在另一端进行删除
    • 栈:只能在表的同一端插入和删除
  • 遍历数据速度不同
    • 队列:基于地址指针进行遍历,可以从头或者尾部进行遍历,不能同时遍历,无需开辟新空间,在遍历过程中不影响数据结构,所以遍历速度快
    • 栈:只能从栈顶取数据,如果要取出栈底的数据,需要遍历整个栈,并且遍历的同时开辟空间,保持遍历前的一致性

8. 区别以下指针类型

int *p[10]     // 指针数组,强调是数组,是一个数组变量,大小为 10,数组内每个元素都是指向 int 类型的指针变量
int (*p)[10]   // 数组指针,强调是指针,只有一个变量,是指针类型,指向的是一个 int 类型的数组,大小是 10
int *p(int)    // 函数声明,函数名是 p,参数是 int 类型,返回值是 int* 类型的
int (*p)(int)  // 函数指针,强调是指针,该指针指向的函数具有 int 类型参数,并且返回值是 int 类型的

9. new/delete 与 malloc/free 的异同

  • 相同点
    • 都可用于内存的动态申请和释放
  • 不同点
    • 前者是 C++ 运算符(支持重载),后者是 C/C++ 语言标准库函数(支持覆盖),需要库文件支持
    • new 自动计算要分配的空间大小,malloc 需要手工计算
    • new 是类型安全的,而 malloc 不是类型安全的
    • new 封装了 malloc,直接 free 不会报错,但是这只是释放内存,而不会析构对象
    • malloc/free 返回的是 void 类型指针(必须进行类型转换),new/delete 返回的是具体类型指针
    • malloc 仅仅分配内存空间,free 仅仅回收空间,new/delete 除了分配回收功能外,还会调用构造/析构函数
    • new 内存分配失败时,会抛出 bac_alloc 异常,malloc 分配内存失败时返回 NULL

10. new 和 delete 是如何实现的

  • new 的实现过程是
    • 首先调用名为 operator new 的标准库函数,分配足够大的原始为类型化的内存,以保存指定类型的一个对象
    • 接下来运行该类型的一个构造函数,用指定初始化构造对象
    • 最后返回指向新分配并构造后的的对象的指针
  • delete 的实现过程
    • 对指针指向的对象运行适当的析构函数
    • 然后通过调用名为 operator delete 的标准库函数释放该对象所用内存

delete 和 delete[] 区别

  • delete 只会调用一次析构函数
  • delete[] 会调用数组中每个元素的析构函数

11. 既然有 malloc/free,C++ 中为什么还需要 new/delete

  • 在使用非基本数据类型的对象时,对象创建时需要执行构造函数,销毁时需要执行析构函数,而 malloc/free 是库函数,是已经编译的代码,不能把构造函数和析构函数的功能强加给 malloc/free,所以 new/delete 是必不可少的

12. 宏定义和(内联)函数的区别

  • 宏定义在预处理阶段完成替换,之后被替换的文本参与编译,相当于直接插入了代码,运行时不存在函数调用,执行起来更快,函数调用在运行时需要跳转到具体调用函数
  • 宏定义没有返回值,函数调用有返回值
  • 宏定义参数没有类型,不进行类型检查,函数参数具有类型,需要检查类型

内联函数在编译时直接将函数代码嵌入到目标代码中,省去函数调用的开销来提高执行效率,并且进行参数类型检查,具有返回值,可以实现重载,内联函数适用场景如下

  • 使用宏定义的地方都可以使用 inline 函数
  • 作为类成员接口函数来读写类的私有成员或者保护成员,会提高效率
  • 不适合使用内联函数的场景:函数体内的代码比较长、函数体内有循环

13. 宏定义和 typedef 的区别

  • 宏定义主要用于定义常量及书写复杂的内容,typedef 主要用于定义类型别名
  • 宏定义替换发生在编译之前,属于文本插入替换,typedef 是编译的一部分
  • 宏定义不检查类型,typedef 会检查数据类型
  • 宏定义不是语句,不在在最后加分号,typedef 是语句,要加分号标识结束

14. 变量声明和定义区别

  • 声明仅仅是把变量的声明位置及类型提供给编译器,并不分配内存空间,定义要在定义的地方为其分配存储空间
  • 相同变量可以在多处声明(外部变量 extern),但只能在一处定义

15. strlen 和 sizeof 区别

  • sizeof 是运算符,并不是函数,strlen 是字符处理的库函数
  • sizeof 参数可以是任何数据的类型或者数据,strlen 的参数只能是字符指针且结尾是 ‘\0’ 的字符串
  • 因为 sizeof 值在编译时确定,所以不能用来得到动态分配(运行时分配)存储空间的大小

16. 一个指针占多少字节

  • 一个指针占内存的大小跟编译环境有关,而与机器的位数无关
    • 32 位编译环境下,指针占用大小为 4 字节
    • 64 位编译环境下,指针占用大小为 8 字节

17. 常量指针和指针常量 & 顶层 const 和底层 const

  • 常量指针和指针常量

    // 从右往左读
    
    // 1、常量指针
    // 指针是个常量,必须初始化,一旦初始化完成,它的值(也就是存放在指针中的地址)就不能再改变,即不能中途改变指向
    // 特点:指针指向的值可以修改,指针指向不可以修改
    int* const p1 = &a;
    *p1 = 100;
    //p1 = &b; 报错
    
    // 2、指针常量
    // 指向一个只读变量的指针
    // 特点:指针指向可以修改,指针指向的值不可修改
    const int* p2 = &a;
    //int const* p2 = &a;  和上一句等价
    p2 = &b;
    //*p2 = 100; 报错
    
    // 3、指向常量对象的常量指针
    // 特点:指针指向不可以修改,指针指向的值也不可修改
    const int* const p3 = &a;
    //*p3 = 100; 报错
    //p3 = &b; 报错
    
  • 顶层 const 和底层 const

    // 顶层 const:const 修饰的变量本身是一个常量,指的是指针
    // 底层 const:const 修饰的变量所指向的对象是一个常量,指的是所指对象(变量)
    int a = 10;
    int* const b1 = &a;        // 顶层 const,b1 本身是一个常量
    const int b3 = 20;         // 顶层 const,b3 是常量不可变
    const int* b2 = &a;        // 底层 const,b2 本身可变,所指的对象是常量
    const int* const b4 = &a;  // 前一个 const 为底层,后一个为顶层,b4 不可变
    const int& b5 = a;         // 用于声明引用变量,都是底层 const
    

18. C++ 和 Python 的区别

  • Python 是一种脚本语言,是解释执行的,而 C++ 是编译语言,是需要编译后在特定平台运行的,python 可以很方便的跨平台,但是效率没有 C++ 高
  • Python 使用缩进来区分不同的代码块,C++ 使用花括号来区分
  • C++ 中需要事先定义变量类型,而 Python 不需要,Python 的基本数据类型只有数字、布尔值、字符串、列表和元组等

19. C++ 和 C 语言的区别

  • C 是 C++ 的子集,C++ 可以很好兼容 C 语言,但 C++ 又有很多新特性如:引用、智能指针、auto 变量等
  • C++ 是面向对象的编程语言,C 语言是面向过程的编程语言
  • C++ 引入了模板的概念,可复用性高,在此基础上实现了方便开发的标准模板库 STL
  • C++ 允许变量定义在程序中的任何地方,只要在使用它之前就可以,而 C 语言必须要在函数开头部分定义变量
  • C++ 除了值和指针外还新增了引用,引用型变量是其他变量的一个别名
  • C++ 可以实现函数重载,C 语言不可以
  • C++ 中 new/delete 是对内存分配的运算符,取代了 C 中的 malloc/free
  • C++ 中用来做控制态输入输出的 iostream 类库替代了C 中的 stdio 函数库

20. C++ 中 struct 和 class 的区别

  • 相同点
    • 两者都拥有成员函数、公有和私有部分,任何可以使用 class 完成的工作,同样可以使用 struct 完成
  • 不同点
    • class 默认是 private 继承,而 struct 默认是 public 继承

C++ 和 C 中的 struct 区别

  • C 中 struct 是没有权限设置的,且 struct 中只能是一些变量的集合体,可以封装数据却不可以隐藏数据,而且成员不可以是函数
  • C++ 中 struct 增加了访问权限,且可以和类一样有成员函数,成员默认访问说明符为public(为了与 C 兼容)
  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值