c语言
【1】struct和class的区别
默认继承访问权限,struct默认是public, class默认是privateg
class可以定义成员函数,struct只能定义成员变量
【2】struct和union的区别
struct的各个成员拥有自的内存,各自使用互不干扰,同时存在,遵循内存对齐原则:一个struct的总长度等于所有成员长度之和
union各个成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权,一个union变量的总长度至少能容纳最大的成员变量,而且要满足所有成员变量类型大小的整数倍。
【3】inline内联函数的作用
内联函数会将代码块嵌入到每个调用该函数的地方,内联函数减少了函数的调用,使代码的执行效率提高,但是会增加目标代码的大小,最终会使程序的代码段占用大量的内存。
【4】模板的优缺点
优点
- 减少代码的复用,节约程序员时间,也是出现标准库的原因
- 免费提高安全性能
缺点
- 只能在编译时才能被确定
【5】const
- 修饰常量时,常量不可变
- 修饰指针时,const在*前,则指针指向的内容为常量,在后则指针本身为常量
- 修饰内对象时,对象中的任何成员都不能被修改,该对象的任何非const成员函数都不能调用该对象,因为任何非const成员函数都会有修改成员变量的可能
- 修饰成员变量时,成员变量不能被修改,只能在初始化列表中被初始化,因为常量只能被初始化,不能被赋值
- 修饰成员函数时,const成员函数不能修改类对象中的任何非const成员变量
c/c++const的区别:
- c语言中const实质上是只读变量
- c++中的const是一个真正意义上的变量
- c++编译器可能为const分配空间
- c++完全兼容c语言中const常量的语法特性
- c语言中的const变量是可以通过指针修改,而c++是不可以的
【6】static
- 在修饰变量时,static的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束后才释放。
- static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其他文件中访问,即便是extern外部声明也不可以,
- static修饰一个函数时,这个函数只能在本文件中调用,不能被其它文件调用。
c++语言
【1】指针和引用的区别
- 引用是别名,指针是地址
- 指针可以为NULL,引用不行
- 引用在创建时必须要初始化,引用到一个有效的对象,指针在定义不必初始化,可以在定义后的任何地方重新赋值,
- 引用的创建和销毁不会调用类的拷贝构造函数和析构函数
- 从内存分配上看,程序为指针变量分配内存区域,而不为引用分配内存
- 指针在运行时可以改变其所指向的值,而引用一旦和某个对象绑定后就不再改变
【2】new, delete, malloc, free区别
- delete会调用对象的析构函数,new会调用构造函数, c++运算符
- free只会释放内存,malloc和free是c语言标准库函数,
- malloc/free无法满足动态对象的要求
【3】虚函数
1.你理解的虚函数和多态
多态的实现主要分为静态多态和动态多态,
静态多态主要是重载,在编译的时候就已经确定;
动态多态是用虚函数机制实现的,在运行期间动态绑定;
虚函数的实现:在有虚函数的类中,类的最开始部分是一个虚函数表的指针,这个指针指向一个虚函数表,表中放了虚函数的地址,实际的虚函数在代码段(.text)中。当子类继承了父类的时候也会继承其虚函数表,当子类重写父类中虚函数时候,会将其继承到的虚函数表中的地址替换为重新写的函数地址。使用了虚函数,会增加访问内存开销,降低效率。
2.虚函数作用及其底层实现原理
c++中虚函数使用虚函数表和虚表指针实现,
虚函数表:是累的虚函数的地址表,用于索引类本身以及父类的虚函数的地址,假如子类的虚函数重写了父类的虚函数,则对应在虚函数表中会把对应的虚函数替换为子类的虚函数地址;
虚函数表指针:存在于每个对象中,它指向对象所在类的虚函数表的地址,
3.为什么析构函数必须是虚函数?为什么c++默认的析构函数不是虚函数
将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。
c++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存,对于不会被继承的类来说,析构函数如果是虚函数,则会浪费内存,只有作为父类时,才设置为虚函数
4.纯虚函数的作用?
5.构造函数用虚函数会怎样?
【4】友元是什么?
友元的作用:可以访问类B里所有的成员变量和成员方法,不管是public, protected还是private
c++11特性
【1】auto 自动类型推导
auto是通过初始化表达式进行类型推导,假设没有初始化表达式,就无法确定类型,不能用作函数传参
decltype, 是为了解决auto只能对变量进行类型推导的缺陷,是从变量或者表达式中获得类型。
decltype(表达式)
【2】nullptr
nullptr的出现目的是为了替代NULL
传统的c++会把null、0视为同一种东西,这取决于编译器如何定义NULL, 有些编译器会将NULL定义为((void*)0)有些直接将其定义为0.
c++不允许直接将void * 隐式转换为其它的类型,但是如果NULL被定义为((void*)0), 那么当编译器 char * ch = NULL时, NULL只好被定义为0;
这会导致重载的特性发生混乱,
void foo(char *);
void foo(int);
对于这两个函数来说,如果NULL又被定义为了0,那么foo(NULL)这个语句将会去调用foo(int),从而导致代码违反直观。
【3】lambda表达式
实际上提供了一个类似匿名函数的特性,(在需要一个函数,但是又不行去费力去命名一个函数的情况下使用)
【4】右值引用
可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提供效率
【5】初始化列表
使用初始化列表来对类进行初始化。
【6】智能指针
auto_ptr: 已被弃用,存在内存奔溃问题,采用了对象所有权机制,资源不能转换
unique_ptr: 对auto_ptr的优化,独享所有权,保证同一时间只能有一个智能指针(unique_ptr)指向该对象, 不允许拷贝与赋值
share_ptr: 多个指针可以共享相同的对象,该对象及资源会在最后一个引用被销毁时释放
但是如果有两个shared_ptr相互引用,那么这两个引用计数永远不为0,资源不被释放
weak_ptr: 解决shared_ptr相互引用时,产生死锁的问题
STL
https://blog.csdn.net/dreamispossible/article/details/89442263
【1】简介stl
- vector: 动态数组,空间连续的,支持随机访问,插入和删除
- list: 双向链表,内存是不连续的,不支持下标访问,支持指针访问
- deque: 双端队列
- map
- set
https://blog.csdn.net/dreamispossible/article/details/89442263