马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
- C++ this指针是干什么用的?
假如一个范例界说了许多对象,类里面有许多界说的私有成员变量,共享一套成员方法。通过this指针这可以区分方法、变量是利用的哪个对象的。
- C++的new和delete,new[]和delete[]可以混用吗?
一般来说operator new 对应 operator delete
new[] 对应 delete[]ptr ,对于内置范例四者相互混用也行。
但是,如果是自界说范例。而且提供了析构函数,那么用new[] 就肯定要用delete[]ptr,不能够混用。
delete相对于free,1.调用析构函数2.开释内存
- C++的static关键字的作用?
从面向过程角度来说:static可以修饰全局变量,函数,局部变量。
对于static修饰全局变量,函数,添加static关键字后变成只当前文件可见,缘故原由:再符号表中符号的作用域就从global变成了local)
对于static修饰局部变量-变量初始化并且初始化不为0的放在了.data段,没有初始化或者初始化为0的放在了.bss端(局部变量不产生符号,在栈上通过ebp-偏移量来访问的)
从面向对象角度来说:static可以修饰成员变量,成员方法(从私有变成共享)修饰成员方法时不会再生成this指针了,直接通过类作用域调用即可。
- C++的继承有什么好处?
继承属于类和类之间的关系(除了继承另有组合)
继承是 a kind of关系 一种
组合是 a part of关系 一部分
继承好处:
代码复用
通过继承,在基类里面给所有派生类可以保存同一的纯虚函数接口,等待派生类举行重写,通过使用多态,可以通过基类指针访问不同派生类对象的同名覆盖方法(做到开闭原则)
- 讲一下C++ 的继承多态
多态:静态多态和动态多态,静态多态是指编译时期的多态,比如函数重载和模板
动态多态是指运行时期的多态,比如虚函数和通过基类指针/引用指向派生类对象
- C++ 空间设置器是什么?
空间设置器allocator:给容器使用的,主要作用就是把内存开辟与对象构造分开,把对象析构和内存开释分离开。
分开缘故原由:当我们去初始化一个容器时,底层应该是空的,只有内存,没有对象,但是如 果在容器构造时直接用new,不仅会开辟内存还会构造许多无用的对象 。当容器删除一个元素时不应该举行内存开释(背面可能会继续使用),只用把对象析构掉即可。
- vector和list的区别?
vector底层数据布局是数组,list底层数据布局是链表。
vector底层内存可以做二倍扩容的数组(内存是一连的),提供了尾部的增加删除利用,时间复杂度都是O(1),适合做随机访问时间复杂度是O(1)(优先级队列是基于vector实现)
list是一个循环的双向链表,适合增加、删除节点,时间复杂度都是O(1)。
- map和多重map?
map:映射表【key-value】底层是由红黑树实现
multimap:唯一一点不同之处就是允许key重复
红黑树:5个性质(每个节点都要有颜色,根节点必须为黑色,叶子节点必须是黑色,从根节点到每一个叶子节点的路径上,不能出现一连的赤色节点,不允许出现两个一连的赤色节点)插入的3种方式(最多旋转2次),删除的4种环境(最多旋转3次)
- C++如何防止内存泄漏?智能指针详述?
内存泄漏:分配到堆内存(没有名字,只能用指针来指向)没有开释,也再没有时机去开释了
智能指针有:
auto_ptr/scoped_ptr/unique_ptr
shared_ptr和weak_ptr
(待补充)
- C++如何调用C语言语句?
C和C++生成符号的方式不同,C和C++语言之间的API接口是无法直接调用的
C语言的函数必须扩在extern"C"{}
- #ifdef __cplusplus
- extern "c"
- {
- #endif
- int sum(int,int); //在C语言下只会根据函数名生成符号,在C++下会根据函数名+参数列表生成符号
- #ifdef __cplusplus
- }
- #endif
复制代码
- C++什么时候会出现访问越界?
系统给我们分配了既定大小的内存,但是在访问内存的时候如果超过了既定内存的大小,就是越界访问了
1.访问数组元素越界
2.vector容器访问-vectorwec; wec[2]越界
3.string str;str[2]
4.array内存不可扩容的数组
5.字符串处理,没有添加’\0’字符,导致访问字符串的时候越界·
6.使用范例强转,让一个大范例(派生类)的指针指向一块小内存(基类对象),然后指针解引用,访问的内存就会越界
- C++中的类的初始化列表?
可以指定对象成员变量的初始化方式,尤其是指定成员对象的构造方式 (初始化先后顺序与界说顺序有关,与在初始化列表里出现的顺序无关)
- C和C++的区别?C和C++的内存分布有什么区别?
1.C++有引用,引用是一种更安全的指针
2.C++支持函数重载
3.C++有new/delete与malloc/free有区别
4.C++有const、inline、带默认值参数的函数
5.C++支持模板,泛型编程
6.C++有类和对象,是OOP语言,可以采取许多设计模式
7.C++支持STL标准模板库,使解决问题更加方便
8.C++有异常机制、智能指针、运算符重载(使对象的运算表现的和内置范例一样)
C和C++的内存分布没有区别,usr space (reserve、.text、.rodata、.bss、heap stack 命令行参数和环境变量)+kernal space(ZONE_DMA 、ZONE_NORAMAL、ZONE_HIGHMEM)
- int* const p和const int* p区别?
const在* 的 右边,右定向 p不能修改,p可以修改
const在 的左边,左定值 p可以修改,*p不能修改
- malloc和new的区别?
1.malloc按字节开辟内存 new底层也是通过malloc开辟内存,但是还可以提供初始化利用
2.malloc开辟内存失败,会返回NULL、new开辟内存失败,会抛出bad_alloc范例的异常
3.malloc现实上是一个C的库函数,operator new是运算符重载函数
4.malloc对于单个或者数组内存开辟方法都一样
- map和set容器的实现原理?
set称作集合,里面只存储、key
map称作映射表,存储【key、value】键值对
两者底层数据布局都是红黑树,
- shared_ptr引用计数存放在那里?
- 18.STL底层
STL包罗标准容器:顺序容器(vector、deque、list)、容器适配器(stack、queue、priority_queue)、关联容器(有序(set、map’)和无序(un))
近容器:数组、string、bitset
迭代器
泛型算法
deque底层是动态开辟的二维数组
- STL中迭代器失效问题?
迭代器是不允许一边读一边修改的
当通过迭代器插入一个元素,所有迭代器就都失效了
当通过迭代器删除一个元素,当前删除位置背面所有元素的迭代器就都失效了
当通过迭代器更新容器元素以后,要及时对迭代器举行更新,insert/ erase方法都会返回新位置的迭代器
- struct和class的区别?
1.界说类的时候,struct默认是公有的,class默认是私有的
2.继承时,如果不写明继承方式,class默认继承方式是私有继承,struct默认是公有继承
3.在C++中struct空布局体是0 struct空类是1
4.C++11初始化可以写成 stuct Data{int ma,int mb} Data data={10,20};
5.class在template还可以界说模板范例参数
- 编译链接全过程?
编译:预编译、编译、汇编、生成二进制可重定位obj文件*.o
链接:归并段,符号解析、符号的重定向生成可执行文件
- 初始化全局变量和未初始化全局变量有什么区别?
初始化而且初始值不为0的放在了.data段
未初始化,初始化位0的放在了.bss段
- 堆和栈的区别?
1.内存大小不同:堆内存的大小远远大于栈内存
2.内存分配方式不同:堆内存是通过malloc和new开辟的,必须手动开释内存free和delete
栈内存是函数的运行在栈上分配栈帧,系统主动分配主动接纳内存
3.内存增长方向不同:堆的内存分配是从低地点到高地点
栈内存分配是从高地点到低地点
4.生存周期不同
- 构造函数和析构函数可不可以是虚函数?
构造函数不可以使虚函数,析构函数可以是虚函数
构造函数不能是虚函数,因为对象还没有构造出来,也就没有虚函数指针,没有虚函数指针也就无法指向虚函数表。
虚析构函数,把基类的析构函数实现成虚析构函数,则对析构函数的调用举举措态绑定,基类、派生类的析构函数就都可以调用到
- 构造函数和析构函数中能不能抛出异常?
构造函数不能抛出异常,如果可以抛出异常的话,假如对象创建失败,则就不会调用析构函数了,从而造成内存泄漏(可以举行代码分离,保证对象创建是乐成的,析构函数也就可以正常执行)
析构函数也不能抛出异常,抛出异常后,析构函数背面资源开释的代码就不会执行了,也会造成造成内存泄漏
所以一般把堆内存用智能指针来代替,确保资源内存正常开释
- 宏和内联函数的区别?
#define和inline
宏是预编译阶段处理(字符串替换)的,宏没有办法举行调试,可以界说常量,代码块,函数块…
内联函数是编译阶段处理(在函数调用点,通过函数的实参把函数代码直接展开调用,节省了函数的调用开销)的,inline函数可以调试(debug版本下inline就和普通函数一样,有标准的函数调用过程),只能用来修饰函数
- 局部变量存放在那里?
局部变量存放stack上,通过ebp指针偏移-4来访问的,不会产生符号
- 拷贝构造函数,为什么传引用不传值?
传值会直接产生编译错误
比如:
- class Test
- {
- public:
- Test(const Test t);
- }
- Test t1;
- Test t2(t1);
- //实际上是 t2.Test(t1)->先用t1拷贝构造形参t const Test t(t1)->t.Test(t1).......无限循环
复制代码
- 内联函数和普通函数的区别?
函数的调用开销
push ebp压入实参
mov ebp esp
sub esp 4Ch开辟栈帧
rep stos 0×CCCCCCCC(Windows)
注意在GCC(gcc/g++下不会做初始化利用)
开释栈
mov esp,ebp esp从栈顶指向栈低
pop ebp epb指向调用方函数的栈低
ret 把下一行指令地点放入寄存器的地点里
- 如何实现一个不可以被继承的类?
派生类的初始化过程是:基类构造然后是派生类构造。所以可以把基类的构造函数私有化
- 什么是纯虚函数?为什么要有纯虚函数?虚函数表放在那里?
virtual void func()=0; -》纯虚函数(抽象类)不能够实例化对象,但是可以界说指针和引用。
一般界说在基类里面。基类不代表任务实体·,它的主要作用之一就是给所有的派生类保存同一的纯虚函数接口,让派生类举行重写方便多态机制使用。因为基类不需要实例化,它的方法也就不知怎么去实现。
虚函数表是在编译阶段产生的,虚函数表运行时加载到.rodata段(只读数据段)
- 手写单例模式
- C++中const,const与static的区别?
const界说的叫做常量,它的编译方式是:编译过程中,把出现常量名字的地方,用常量的值举行替换
- const int a = 10;
- int *p = (int*)&a;
- *p = 20;
- cout<<"a = "<<a<<"*p= "<<*p<<endl;
- //结果是 a = 10 *p = 20
复制代码- int b =3;
- const int a = b; //此时a叫做常变量
- int *p = (int*)&a;
- *p = 20;
- cout<<"a = "<<a<<"*p= "<<*p<<endl;
- //结果是 a = 20 *p = 20
复制代码 const还可以界说常成员方法 -this指针从Test* this =》 const Test * this普通对象和常对象就都可以调用了
const和static的区别
从面向过程来说:
const只能修饰全局变量、局部变量、形参变量
static可以修饰全局变量、局部变量
const:不能修饰函数
static 可以修饰函数,改变符号的作用域,改成只本文件可见
从面向对象来说:
const修饰的叫常方法(普通对象和常对象就都可以调用,但是只能举行读利用,不能举行写利用)/常成员变量(不能别修改的变量,必须在构造函数初始化列表中界说)都依赖于对象
static修饰的叫静态方法(本质是this指针没有了,不依赖于对象,通过类作用域访问)/静态成员变量
- 四种强制范例转换?
const_cast:去掉常量属性
static_cast: 范例安全转换
reinterpret_cast:C风格范例转换
dynamic_cast:支持RTTI信息辨认的范例转换
- 具体表明deque的底层原理
底层是动态开辟的二维数组
#define MAP_SIZE 2 //MAP_SIZE (T*)一维数组的大小
#define QUE_SIZE(T) 4096/sizeof(T) //二维数组开辟的大小
deque是双端队列,两端都有对头和队尾。两端都可以插入删除,时间复杂度是O(1)
扩容:第一维数组按照2倍方式举行扩容2-4-8…
扩容以后会把原来的第二维的数组,从新一维数组的oldsize/2 开始存放,也就是从中间开始存放,为了首尾插入方便。
deque的内存使用率比较好,刚开始就有一段内存可以提供使用
- 虚函数?
一个类如果有虚函数,那么在编译阶段就要产生一张虚函数表,在运行的时候加载到.rodata段
用指针或者引用时,来调用虚函数时,通过指针访问对象的头四个字节·vfptr去相应的vftable中取虚函数的地点举举措态绑定调用
- 一个类,写一个构造函数,又写了一个虚构造函数,可不可以?会发生什么?
虚函数的调用条件是对象存在,
一个派生类的构造要先调用基类构造函数,如果基类是虚构造函数则会无限循环
在构造函数中,是不会举举措态绑定的,虚构造函数本身也不能实现成虚函数。
- 异常是怎么回事?
- try
- {
- 可能会抛出的异常代码
- }
- catch(const string& err)
- {
- 捕获相应异常类型对象,进行处理,完成后,继续向下运行
- }
复制代码 异常的栈展开:
在当前函数栈帧上没有找到相应的catch块处理,就会把异常抛给调用方函数,调用方依然安装这样的逻辑来处理,如果捕获相应异常范例对象,则举行处理,完成后,继续向下。如果还没有找到,依然会抛给调用方,反复判断处理,直到到达main主函数,再抛给系统,直接停止进程。
可以把代码中所有的可能发生的异常抛出到同一的地方举行处理,不会出现问题就随时exit(0);
- 早绑定和晚绑定?
早绑定(静态绑定): 编译时期的绑定,普通函数的调用,用对象调用虚函数,在Call编译阶段就已经知道调用的那个函数了
晚绑定(动态绑定):用指针/引用调用虚函数的时候,都是动态绑定
p->vfptr->vftable->virtual addr->call eax
- 指针和引用的区别?
从反汇编角度分析:
- int a =10;
- int* p = &a;
- int &q = a;
- //前面两句在汇编指令上完全一致的 把a的内存拿出来放在寄存器,再把寄存器的值放在底层的4字节的指针变量
- lea eax,[a] mov dword ptr[ebp-8],eax
- lea eax,[a] mov dword ptr[ebp-0Ch],eax
- *p = 20;
- q = 20;
- //指令也一样,先从底层4字节的指针里面拿出来引用内存的地址,再把20写到4字节内存的地址里面
- mov eax,dword ptr[ebp -8] mov dword ptr[eax],14H
- mov eax,dword ptr[ebp -0Ch] mov dword ptr[eax],14H
复制代码 界说对象的时候使用强智能指针shared_ptr
引用对象的时候用弱智能指针weak_ptr
当通过weak_ptr访问对象成员时,需要先调用weak_ptr的lock提升方法,把weak_ptr提升成shared_ptr智能指针,再举行对象成员的调用
- 重载的底层实现?
C++生成函数符号,是依赖于函数名字+参数列表
当我们编译到函数调用点时,根据函数名字和传入的实参(范例,个数)和某一个函数重载匹配的话,就直接调用相应的函数重载版本(静态多态,都是在编译阶段处理的)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |