2021-06-23

**

语言基础(C++)

**

(1) 指针和引用的区别

(1)指针有自己的一块空间,而引用只是一个别名;
(2)使用 sizeof 看一个指针的大小为4字节(32位,如果要是64位的话指针为8字节),而引用则是被引用对象的大小。
(3)指针可以被初始化为 NULL,而引用必须被初始化且必须是一个已有对象的引用。
(4)作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用的修改都会改变引用所指向的对象。
(5)指针在使用中可以指向其他对象,但是引用只能是一个对象的引用,不能被改变。
(6)指针可以是多级,而引用没有分级
(7)如果返回动态分配内存的对象或者内存,必须使用指针,引用可能引起内存泄漏。

(2) 堆和栈的区别

(1)堆栈空间分配区别:

~栈(操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;
~堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
(2)堆栈的缓存方式区别

~栈:是内存中存储值类型的,大小为2M(window,linux下默认为8M,可以更改),超出则会报错,内存溢出
~堆:内存中,存储的是引用数据类型,引用数据类型无法确定大小,堆实际上是一个在内存中使用到内存中零散空间的链表结构的存储空间,堆的大小由引用类型的大小直接决定,引用类型的大小的变化直接影响到堆的变化
(3)堆栈数据结构上的区别

堆(数据结构):堆可以被看成是一棵树,如:堆排序;
栈(数据结构):一种先进后出的数据结构。

(3) new和delete是如何实现的,new 与 malloc的异同处

new操作针对数据类型的处理,分为两种情况:

(1) 简单数据类型(包括基本数据类型和不需要构造函数的类型)

~简单类型直接调用 operator new 分配内存;
~可以通过new_handler 来处理 new 失败的情况;
~new 分配失败的时候不像 malloc 那样返回 NULL,它直接抛出异常(bad_alloc)。要判断是否分配成功应该用异常捕获的机制;
(2)复杂数据类型(需要由构造函数初始化对象)

new 复杂数据类型的时候先调用operator new,然后在分配的内存上调用构造函数。
delete也分为两种情况:

(1) 简单数据类型(包括基本数据类型和不需要析构函数的类型)

delete简单数据类型默认只是调用free函数。
(2)复杂数据类型(需要由析构函数销毁对象)

delete复杂数据类型先调用析构函数再调用operator delete。
从原理上来分析可以看看这篇博客:C++ new和delete的实现原理

与 malloc 和 free 的区别:

(1)属性上:new / delete 是c++关键字,需要编译器支持。 malloc/free是库函数,需要c的头文件支持。
(2)参数:使用new操作符申请内存分配时无须制定内存块的大小,编译器会根据类型信息自行计算。而mallco则需要显式地指出所需内存的尺寸。
(3)返回类型:new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,故new是符合类型安全性的操作符。而malloc内存成功分配返回的是void *,需要通过类型转换将其转换为我们需要的类型。
(4)分配失败时:new内存分配失败时抛出bad_alloc异常;malloc分配内存失败时返回 NULL。
(5)自定义类型:new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。 malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
(6)重载:C++允许重载 new/delete 操作符。而malloc为库函数不允许重载。
(7)内存区域:new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。其中自由存储区为:C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。

(4) C和C++的区别

1.C语言是C++的子集,C++可以很好兼容C语言。但是C++又有很多新特性,如引用、智能指针、auto变量等。
2.C++是面对对象的编程语言;C语言是面对过程的编程语言。
3.C语言有一些不安全的语言特性,如指针使用的潜在危险、强制转换的不确定性、内存泄露等。而C++对此增加了不少新特性来改善安全性,如const常量、引用、cast转换、智能指针、try—catch等等;
4.C++可复用性高,C++引入了模板的概念,后面在此基础上,实现了方便开发的标准模板库STL。C++的STL库相对于C语言的函数库更灵活、更通用。

(6) Struct和class的区别

(1)首先说一下C中的结构体和C++中的结构体的异同:
在这里插入图片描述
(2)C++中 struct 与 class 的区别:

1、内部成员变量及成员函数的默认访问属性:struct 默认防控属性是 public 的,而 class 默认的访问属性是private的
2、继承关系中默认访问属性的区别:在继承关系,struct 默认是 public 的,而 class 是 private
3、class这个关键字还可用于定义模板参数,就等同于 typename;而strcut不用与定义模板参数

(7) define 和const的区别(编译阶段、安全性、内存占用等)

(1)起作用的阶段: #define是在编译的预处理阶段起作用,而const是在编译、运行的时候起作用。
(2)作用的方式:const常量有数据类型,而宏常量没有数据类型,只是简单的字符串替换。编译器可以对前者进行类型安全检查。而对后者没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。
(3)存储的方式:#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若干个备份;const定义的只读变量在程序运行过程中只有一份备份,const比较节省空间,避免不必要的内存分配,提高效率。

(8)在C++中const和static的用法(定义,用途)

(1)static:

1、修饰全局变量:存储在静态存储区;未经初始化的全局静态变量自动初始化为 0;作用域为整个文件之内。
2、修饰局部变量:存储在静态存储;未经初始化的局部静态变量会被初始化为0;作用域为局部作用域,但离开作用域不被销毁。
3、修饰静态函数:静态函数只能在声明的文件中可见,不能被其他文件引用
4、修饰类的静态成员:在类中,静态成员可以实现多个对象之间的数据共享,静态成员是类的所有对象中共享的成员,而不属于某一个对象;类中的静态成员必须进行显示的初始化
5、修饰类的静态函数:静态函数同类的静态成员变量一个用法,都是属于一个类的方法。而且静态函数中只可以使用类的静态变量。
(2)const:

1、修成类成员:在C++中,const成员变量也不能在类定义处初始化,只能通过构造函数初始化列表进行,并且必须有构造函数; const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。
2、修饰类函数:该函数中所有变量均不可改变。

(9) const和static在类中使用的注意事项(定义、初始化和使用)

定义:
const可以在类内部定义,但是定义的位置不能初始化;static只能在类内部声明,定义只能在类的外面,并且定义的时候不能加static关键字

初始化:
const不能再定义的位置初始化,只能在类的构造函数的初始化列表中初始化;static初始化不能再类的内部进行初始化,必须在外部定义的时候初始化。

使用:
const的使用主要目的是防止成员函数修改对象的内容,即const成员函数不能修改成员变量的值,但可以访问成员变量。
static的使用目的是作为类作用域的全局函数。不能访问类的非静态数据成员,类的静态成员函数没有this指针,这导致不能直接存取类的非静态成员变量,调用非静态成员函数,不能声明为virtual.

(10) C++中的const类成员函数(用法和意义)

1.void fun() const;
表明是常量成员函数,这个const表明了该函数不会改变任何成员数据的值。
2.void fun(const a) const;
表明是参数是常量的常量成员函数,接收的参数是常量,同时不能改变成员数据的值。

意义:为什么要这么做?
这是为了保证它能被const常量对象调用,我们都知道,在定义一个对象或者一个变量时,如果在类型前加一个const,如const int x;,则表示定义的量为一个常量,它的值不能被修改。但是创建的对象却可以调用成员函数,调用的成员函数很有可能改变对象的值。所以这个时候const类成员函数就出现了。

于是,我们把那些肯定不会修改对象的各个属性值的成员函数加上const说明符,这样,在编译时,编译器将对这些const成员函数进行检查,如果确实没有修改对象值的行为,则检验通过。以后,如果一个const常对象调用这些const成员函数的时候,编译器将会允许。

(13) C++的STL介绍(这个系列也很重要,建议侯捷老师的这方面的书籍与视频),其中包括内存管理allocator,函数,实现机理,多线程实现等

链接: link.
标准模板库(Standard Template Library,简称STL)简单说,就是一些常用数据结构和算法的模板的集合。
广义上讲,STL分为3类:Algorithm (算法)、Container(容器)和lterator(迭代器),容器和算法通过迭代器可以进行无缝地连接。
详细的说,STL由6部分组成:容器(Container)、算法(Algorithm)、迭代器(lterator)、仿函数(Function object)、适配器(Adaptor) 、空间配制器(Allocator) .
标准模板库STL主要由6大组成部分:
1.容器(Container)
是一种数据结构,如list, vector,和deques,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器。
⒉.算法(Algorithm)
是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以用于从简单数组到高度复杂容器的任何数据结构上。
3.迭代器(Ilterator)
提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符方法的类对象;
4.仿函数(Function object)
仿函数又称之为函数对象,其实就是重载了操作符的struct,没有什么特别的地方。
5.适配器(Adaptor)
简单的说就是一种接口类,专门用来修改现有类的接口,提供一中新的接口;或调用现有的函数来实现所需要的功能。主要包括3中适配器Container Adaptor、Iterator Adaptor、FunctionAdaptor.
6.空间配制器(Allocator)
为STL提供空间配置的系统。其中主要工作包括两部分:(1〕对象的创建与销毁;(2)内存的获取与释放。

(14)STL中map hashtable deque list 的实现原理

在这里插入图片描述

(15) STL中unordered_map和map的区别

https://www.cnblogs.com/OFSHK/p/14542522.html

(17) vector使用的注意点及其原因,频繁对vector调用push_back()对性能的影响和原因。

在这里插入图片描述
在这里插入图片描述

(18) C++中的重载和重写的区别:

在这里插入图片描述
在这里插入图片描述

(19)C ++内存管理(热门问题)

在这里插入图片描述

(20) 介绍面向对象的三大特性,并且举例说明每一个。

在这里插入图片描述

(21) 多态的实现(和下个问题一起回答)

在这里插入图片描述
在这里插入图片描述

(22) C++虚函数相关(虚函数表,虚函数指针),虚函数的实现原理(热门,重要)

在这里插入图片描述
在这里插入图片描述

(23) 实现编译器处理虚函数表应该如何处理

1)通常,编译器给类的每个对象添加一个隐藏的成员,这个成员保存了一个指向虚函数表〈virtual function table , vtbl)的指针,而虚函数表中保存了类对象进行声明的虚函数的地址。也就是说我们可以通过这个隐藏成员访问虚函数表,进而访问被声明的虚函数的地址,从而调用虚函数。
在这里插入图片描述

(24) 析构函数一般写成虚函数的原因

在这里插入图片描述

(25) 构造函数为什么一般不定义为虚函数

在这里插入图片描述

(26) 构造函数或者析构函数中调用虚函数会怎样

在这里插入图片描述

(27) 纯虚函数

在这里插入图片描述

(28) 静态绑定和动态绑定的介绍

https://blog.csdn.net/zshuaihua/article/details/52749652?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-2.base

(29) 引用是否能实现动态绑定,为什么引用可以实现

可以实现,因为动态绑定是发生在程序运行阶段的,c++中动态绑定是通过对基类的引用或者指针调用虚函数时发生。
因为引用或者指针的对象是可以在编译的时候不确定的,如果是直接传对象的话,在程序编译的阶段就会完成,对于引用,其实就是地址,在编译的时候可以不绑定对象,在实际运行的时候,在通过虚函数绑定对象即可。

(30) 深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)

在这里插入图片描述

(31) 对象复用的了解,零拷贝的了解

零拷贝:零拷贝主要的任务就是避免CPU将数据从一块存储拷贝到另外一块存储,主要就是利用各种零拷贝技术,避免让CPU做大量的数据拷贝任务,减少不必要的拷贝,或者让别的组件来做这一类简单的数据传输任务,让CPU解脱出来专注于别的任务。这样就可以让系统资源的利用更加有效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值