0
点赞
收藏
分享

微信扫一扫

【面经】C/C++零散笔记

尤克乔乔 2022-03-12 阅读 94
.1. 构造函数和析构函数
.2. 动态链接和静态链接区别
  • 静态链接:编译时直接将需要执行代码拷贝到调用处,体积大,独立运行
  • 动态链接:编译时不直接拷贝执行代码,而是通过记录一系列符号和参数,在程序运行时加载这些信息,,操作系统负责将需要的动态链接库加载到内存中。 运行需要加载。
.3. c 和C++ 区别
  • C++ 是面向对象的语言,而 C 是面向过程的语言;
  • C++ 引入 new/delete 运算符,取代了 C 中的 malloc/free 库函数;
  • C++ 引入引用的概念,而 C 中没有;
  • C++ 引入的概念,而 C 中没有;
  • C++ 引入函数重载的特性,而 C 中没有
.4. 变量的声明和定义区别
  • 定义:为变量分配地址和存储空间,
  • 声明:不分配地址
  • 可以多个声明,只能有一个定义, 一般在具体使用时才初始化
.5. 引用和指针区别
  • 指针是一个实体,引用是别名
  • 指针可以为空,引用不可以
  • “sizeof 引用” 得到的是所指向的变量 (对象) 的大小,而 “sizeof 指针” 得到的是指针本身 (所指向的变量或对象的地址) 的大小;
  • 从内存分配上看:程序为引用变量分配内存区域,而指针不需要分配内存区域
  • 指针和引用的自增 (++) 运算,意义一样
.6. Struct 和Public 区别

struct 作为数据结构的实现体,它默认的数据访问控制是 public 的,而 class 作为对象的实现体,它默认的成员变量访问控制是 private

.7. C++ 多态(静态和动态)
  • 不同对象发送同一个消息,不同对象会做出不同的响应
  • 静态多态就是在系统编译期间就可以确定程序执行到这里将要执行哪个函数,例如:函数的重载,对象名加点操作符执行成员函数等,都是静态多态,其中,重载是在形成符号表的时候,对函数名做了区分,从而确定了程序执行到这里将要执行哪个函数,对象名加点操作符执行成员函数是通过 this 指针来调用的。
  • 虚函数就是在基类中声明该函数是虚拟的(在函数之前加 virtual 关键字),然后在子类中正式的定义(子类中的该函数的函数名,返回值,函数参数个数,参数类型,全都与基类的所声明的虚函数相同,此时才能称为重写,才符合虚函数,否则就是函数的重载),再定义一个指向基类对象的指针,然后使该指针指向由该基类派生的子类对象,再然后用这个指针来调用改虚函数,就能实现动态多态
  • 都能够使接口和实现相分离,一个是模板定义接口,类型参数定义实现,一个是基类虚函数定义接口,继承类负责实现;
  • 虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针
.8. malloc 和 new 区别
  • new/deleteC++ 关键字,需要编译器支持。malloc/free 是库函数,需要头文件支持
  • 使用 new 操作符申请内存分配时无须指定内存块的大小编译器会根据类型信息自行计算。而 malloc 则需要显式地指出所需内存的尺寸
  • new 操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故 new 是符合类型安全性的操作符。而 malloc 内存分配成功则是返回 void *,需要通过强制类型转换将 void * 指针转换成我们需要的类型
  • new 内存分配失败时,会抛出 bad_alloc 异常malloc 分配内存失败时返回 NULL
.11. 智能指针, 目的
  • 智能指针的作用是管理一个指针, 申请的空间在函数结束时忘记释放,造成内存泄漏。
  • 能指针是一个类,当超出了类的实例对象的作用域时,会自动调用对象的析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
.12. 面向过程和面向对象的区别
  • 面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数。
  • 面向对象是一种以 “对象” 为中心的编程思想,把要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个对象在整个解决问题的步骤中的属性和行为
.13. 虚函数,虚函数底层实现原理
.14. 重载和重写区别, 多个重载如何找到
  • 重载:

    • 参数列表:被重载的方法必须改变参数列表
    • 返回类型:可以改变返回类型
    • 修饰符:可以改变修饰符
    • 异常:可以声明新的或者更广泛的异常
  • 重写:(多继承)

    1. 参数列表:必须与被重写方法的参数列表完全匹配

    2. 返回类型:必须与超类中被重写的方法中声明的返回类型或子类型完全相同

    3. 访问级别:一定不能比被重写方法强,可以比被重写方法的弱。

    4. 非检查异常:重写方法可以抛出任何非检查的异常,无论被重写方法是否声明了该异常。

    5. 检查异常:重写方法一定不能抛出新的检查异常,或比被重写方法声明的检查异常更广的检查异常。

    6. 不能重写标志为 final, static 的方法。

.16. 类对象的内存分布与生存周期
.17. C++ 内存管理
  • text (代码段): 用来存放程序执行代码,同时也可能会包含一些常量 (如一些字符串常量等)。该段内存为静态分配,只读 (某些架构可能允许修改)
  • data (数据段):用来存放程序中已经初始化的非零全局变量,静态分配。data 又可分为读写(RW)区域和只读(RO)区域,RO 段保存常量所以也被称为.constdata,RW 段则是普通非常全局变量,静态变量就在其中
  • bss:存放程序中未初始化的和零值全局变量。静态分配,在程序开始时通常会被清零。
  • 堆:在内存开辟另一块存储区域,般由程序员分配释放, 若程序员不释放,程序结束时可能由 OS 回收
  • 栈:程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等
.18. 内存对齐
  • 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
  • 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问

如何对齐:

  • 分配内存的顺序是按照声明的顺序
  • 每个变量相对于起始位置的偏移量必须是该变量类型大小的整数倍,不是整数倍空出内存,直到偏移量是整数倍为止
  • 最后整个结构体的大小必须是里面变量类型最大值的整数倍
.19. 类型转化
  1. const_cast: 用于将 const 变量转为非 const
  2. static_cast: 用于各种隐式转换
  3. dynamic_cast: 用于动态类型转换。只能用于含有虚函数的类
  4. reinterpret_cast: 几乎什么都可以转
.20 构造函数可以是虚函数
  • 析构函数可以,构造函数不行
  • 虚函数的调用需要虚函数表指针,而该指针存放在对象的内容空间中;若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有虚函数表地址用来调用虚函数 —— 构造函数了。
22. 类为空的时候编译器怎么初始化?
  • 空类是没有数据成员,没有函数的类
  • 空类或者空类对象的大小(无继承情况下):编译器会在空类中安插一个 char,使得这个空类的两个 objects 得以在内存中配置独一无二的地址。只有当一个类为空的时候,编译器才会向该类中加入这样一个 char
  • 空类或者空类对象的大小(有继承但无虚继承情况下):继承的基类都是空类,大小是 *1*,不管有多少个父类。
  • 空类或者空类对象的大小(单一虚继承情况下):对每一个虚继承基类,都有一个虚基类索引 (或者偏移量、指针),占 4 字节
23. 32 位机和 64 位机的区别
24.拷贝构造函数和赋值构造函数
  • 都是将一个对象的值复制给另一个对象
  • 拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例
  • 主要是看是否有新的对象实例产生。如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。
25. 什么是页表,同一进程的不同线程是否共享页表
25. find_package原理
set(Caffe_DIR /home/wjg/projects/caffe/build)   #添加CaffeConfig.cmake的搜索路径
find_package(Caffe REQUIRED)     # 这个命令
if (NOT Caffe_FOUND)
    message(FATAL_ERROR "Caffe Not Found!")
endif (NOT Caffe_FOUND)
include_directories(${Caffe_INCLUDE_DIRS})
add_executable(useSSD ssd_detect.cpp)          # 添加可执行文件
target_link_libraries(useSSD ${Caffe_LIBRARIES})  # 连接所需要的库文件

# 创建共享库(把工程内的cpp文件都创建成共享库文件,方便通过头文件来调用)
add_library(${PROJECT_NAME} SHARED
src/cpp文件名
……
)
# 头文件
include_directories("路径")
# 把刚刚生成的${PROJECT_NAME}库和所需的其它库链接起来
target_link_libraries(${PROJECT_NAME}
/usr/lib/i386-linux-gnu/libboost_system.so
举报

相关推荐

【面经】JVM零散整理

c++零散知识点

零散笔记

c++零散知识点整理

C++面经

C++ 面经总结

0 条评论