C++知识点复习(面向面试1) 今天开始我将开一个专栏用来复习C的一些知识点主要是面向面试的一些八股希望对大家有所帮助也能更好地激发我的热情。今天复习的知识点有五条我们都从原理到底层剖析如果有错误也请大家指正。1.C语言和C的区别2.函数重载问题3.引用4.面向对象三大特征5.new和malloc的区别好的我们从第一条开始。今天复习的知识点有五条我们都从原理到底层剖析如果有错误也请大家指正。1.C语言和C的区别第一点关乎到编程思维的C语言是面向过程编程C是面向对象编程。C语言的核心是函数他把程序看为线性的步骤数据和行为是分离的你要把数据看为原料喂养给函数去处理。C语言要求你对每一行代码了如指掌你得从0开始构建设计因此非常适合逻辑直接追求底层效率的代码比如操作系统内核嵌入式驱动因为它需要你精确控制每一块内存和每一个CPU指令。C的核心是对象在C语言的基础上提倡把数据和操作结合在一起他关心的是如何把一个复杂的操作拆解成为一个个类和模块你只要知道那个部分完成什么事情就行了这使得大型项目的维护变得简单。C语言怎么做How to do itC谁来做Who does it。第二点C带来的高级工具。面向对象的三大特点函数重载引用STL容器库。这些工具不多一一赘述我们后面的复习也会反复提起。第三点关于内存管理C语言只能靠malloc和free来申请和释放。C语言提供了更多内存管理的方法new/delete来自动调用构造和析构。以及现代C推崇的智能指针来自动管理内存生命周期。第四点一些细小的语法细节。首先C语言的头文件不带.hC语言没有bool类型NULL在C语言里是void*0而在C里面则是0C11后引入了nullptr来解决这个问题。C不允许隐式类型转换自动推导auto协助循环编写在面试中提起也是加分项。简单总结一下1.C语言面向过程编程C面向对象编程封装继承多态。2.C语言不能函数重载C可以。3.C语言没有bool类型。4C语言头文件带.h,C不带。5.C不能隐式转换。2.函数重载问题什么是函数重载指的是在一个作用域中函数名字相同参数的个数顺序或类型其中一个不同则为函数重载函数重载与返回值无关。C为什么能实现函数重载C编译器在编译函数的时候会在原来名字的基础上加上参数类型来识别不同的重载函数但是C语言函数名在被定义成什么编译后仍然是原名所以C语言不能重载。如何理解重载是静态多态静态指的是绑定的时间是在编译期编译器在运行的时候会直接查找运行调用的地址是固定的。底层实现是编译器根据参数签名直接替换成具体函数地址。与之对应的重写动态多态底层实现是靠虚函数表vtable在运行时查表跳转。静态多态是看参数的实际类型。动态多态则是看对象的实际类型。3.引用什么是引用引用的本质是在给变量起别名。引用和原变量共用一块内存空间对引用的任何操作本质上是对原变量的操作。引用有三大铁律1.定义时必须初始化 2.引用初始化不能为空必须绑定到一块有效的内存地址 3.不能修改引用关系一旦绑定终生不变。引用的底层是一个被优化和封装的指针常量。引用的类型1.左值引用避免拷贝起别名。2.右值引用给一个临时对象起别名获取内部资源而不是进行深拷贝。3.万能引用实现完美转发。应用的用处1.用于函数参数代替指针。如果在函数内部想修改外部的变量使用指针需要取地址函数内部还需要解引用但是用引用就十分方便。2.避免拷贝构造如果传递的是一个非常大的对象传值会出触发深拷贝但是传引用只传递地址。3.用于函数的返回值函数的返回值本身是右值使得函数返回值是左值可以返回引用类型。引用和指针的区别引用不可以为空指针可以为空。引用定义时必须初始化指针不用。引用不可以改变指向指针可以改变指向。引用没有多级指针有多级。指针需要显式解引用引用编译器自行处理。sizeof引用得到的是引用指向变量的大小sizeof指针得到的是指针变量本身的大小。引用比指针更安全使用形式上更加方便整洁。指针作为函数参数传递的时候传递的是指针变量的值而引用作为函数参数传递的时候传递的是实参本身。4.面向对象的三大特征封装将事物的属性成员变量和行为成员函数封装在一起形成一个类。并且可以设置相应的访问权限私有 受保护 公有。继承可以通过现有的类来实现新的类相当于对现有的类进行扩展提高了代码的复用性可维护性是多态的前提多继承问题 菱形继承问题。多态父类的指针或引用指向子类对象开启多态的前提条件是调用重写的函数。可以让同一个行为在不同的对象上有不同的表现。5.new和malloc的区别malloc是C语言留给我们的底层工具new是C为了面对对象特性实现的高级封装。从底层来讲malloc是标准库函数向操作系统申请一块指定大小的内存。new是C运算符它在底层其实做了两步操作。当你执行 new 时编译器会先调用底层的 operator new 函数operator new 内部其实封装了 malloc 来分配内存内存分配成功后紧接着会自动调用对象的构造函数。● new 的返回值不需要强制转换malloc 的返回值需要强制转换。new返回的是具体的对象类型指针如 int*不需要强制转换编译器会自动进行严格的类型检查。malloc返回的是 void*无类型指针。在 C 语言中 void* 可以隐式转换但在 C 这种强类型语言中必须显式地强制转换成目标类型如 (int*)malloc(...)否则编译不通过。● new 是运算符可以重载重载是静态多态引导说多态malloc 是库函数malloc 不能重载因为他是 c 语言的库函数可以说 C 和 C编译方式的区别● new 不需要传入想要申请的具体字节个数malloc 需要传入想要申请的具体字节个数。new非常智能编译器会根据你指定的类型自动计算需要多少个字节。malloc非常原始必须你手动计算并传入具体的字节数比如 malloc(10 * sizeof(int))一旦算错就会导致缓冲区溢出。● malloc 申请失败例如传入参数是负数的情况下返回空new 申请失败会抛出异常引出异常机制以及自定义异常类如何实现。new申请失败默认会抛出 std::bad_alloc 异常。你可以用 try-catch 块来捕获并处理。malloc手动判空后续解引用会直接崩溃。● 如果给一个类分配堆区内存new会先调用malloc 分配内存然后再调用构造函数给成员变量赋值注意构造函数给成员变量赋值可以引出初始化参数列表是初始化。new分两步走。先分配原始内存然后自动调用类的构造函数。这里有个细节在构造函数体内写 a 10 其实叫“赋值”而初始化参数列表: a(10)才是真正的“初始化”。对于 const 成员、引用成员或者没有默认构造函数的类成员必须使用初始化列表。malloc只做一件事——分配一块未初始化的原始内存。它完全不会调用构造函数所以如果用 malloc 给一个 C 对象分配内存这个对象内部的成员变量都是垃圾值直接操作极其危险。● new 申请的堆区内存需要使用 delete 释放delete 先调用析构函数再调用 freefree也是 c 语言库函数和 malloc 是配套的这里可以说一下为什么先调用析构再调用 free。你可以把 C 的对象想象成“一个带保险箱的房间”对象的内存空间 房间本身。对象的内部资源比如在构造函数里 new 出来的堆内存、打开的文件等 房间里保险箱的钥匙和贵重物品。析构函数 负责把保险箱里的东西清空、把钥匙销毁的“清理程序”。free 负责把整个房间推倒、归还给地基的“拆迁队”。如果先调用 free拆迁队先来房间对象内存直接被推倒销毁了但保险箱的钥匙内部资源的指针还没来得及处理。这时候钥匙指向的保险箱虽然还在但你已经失去了对房间的控制权钥匙变成了“野指针”。那些没被清理的贵重物品内部资源就永远遗留在废墟里没人能回收——这就是典型的内存泄漏。正确的顺序先析构再 free先调用析构函数清理程序先进房间把保险箱里的东西清空把钥匙销毁释放对象内部申请的资源。再调用 free拆迁队再来把空荡荡的房间推倒归还内存。所以new 和 delete 是一套完整的、有生命周期的对象管理机制而 malloc 和 free 只是单纯的内存块搬运工。这就是今天的所有知识点希望可以帮助到你我们明天见