强制类型转换运算符,C的强转对应哪个?
c++里面的的类型转换符有四个,分别是const_cast、static_cast、dynamic_cast、reinterpret_cast。这四种类型分别有不同的作用。
const_cast:一般用于去除const属性,将const转换为非const,但原变量的属性还是const,只是在强转的过程中会临时生成一份去除const属性的变量出来。static_cast:用于强制转换数据类型,但是没有运行时的安全检测,而且还不能进行交叉转换,意思就是不是同意继承体系的无法转换,常用于基本数据类型的转换吗、非const转换constdynamic_cast:使用最多的一个类型转换符,一般用于多态类型的转换,有运行时安全检测reinterpret_cast:属于比较底层的进制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝;可以交叉转换,可以将指针和整数相互转换。
而c语言的强转对应的就是static_cast,原因是他们两个在强转的时候都不会进行类型强转的安全检测,类型不匹配的话就会报异常。
智能指针
智能指针主要用于管理在堆上分配的内存,它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存,从而防止内存泄漏。C++ 11中最常用的智能指针类型为shared_ptr,它采用引用计数的方法,记录当前内存资源被多少个智能指针引用。该引用计数的内存在堆上分配。当新增一个时引用计数加1,当过期时引用计数减一。只有引用计数为0时,智能指针才会自动释放引用的内存资源。对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。
在使用传统的指针的时候很容易出现以下问题:
- 需要手动管理内存
- 容易发生内存泄漏(忘记释放、出现异常等)
- 释放之后产生野指针
而只能指针的出现就是为了解决传统指针出现的问题,智能指针分别有:shared_ptr、weak_ptr、 unique_ptr。
shared_ptr的原理
- 一个
shared_ptr会对一个对象产生强引用 - 每个对象都有个与之对应的强引用计数,记录着当前对象被多少个
shared_ptr强引用着- 可以通过
shared_ptr的use_count函数会的强引用计数
- 可以通过
- 当有一个新的
shared_ptr指向对象时,对象的强引用计数就会+1 - 当有一个
shared_ptr销毁时(比如说作用域结束),对象的强引用计数就会-1 - 当一个对象的强引用计数为0时(没有任何
shared_ptr指向对象时),对象就会自动销毁(调用析构函数)。
使用shared_ptr时避免循环引用,循环引用会导致堆内存无法正确释放,导致内存泄漏。
weak_ptr的原理
weak_ptr 的实现原理同shared_ptr会差不多,不过weak_ptr产生的是弱引用,它可以用来解决shared_ptr的循环引用问题
unique_ptr的原理
unique_ptr也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象- 当
unique_ptr销毁时(作用域结束),其指向的对象也就自动销毁了。 - 可以使用std::move函数转移
unique_ptr的所有权(转移强引用对象)
TCP和UDP的区别
TCP面向连接(如打电话先要拨号建立连接);UDP是面向无连接,即发送数据前不需要建立连接TCP提供可靠的服务,也就是说通过TCP连接传送的数据,无差错,不丢失,不重复,且按顺序到达;UDP进最大努力交付,但不保证可靠交付。TCP面向字节流,实际上是TCP把数据看成一串无结构的字节流;UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)- 每一条
TCP连接只能是点到点的;UDP支持一对一,一对多,多对一的交互通信 TCP首部开销20字节;UDP首部开销小,只有8个字节TCP的逻辑通信信道是全双工的可靠信道;UDP则是不可靠信道。
C++编译过程
c++编译分为以下四个步骤:预处理-->编译-->汇编-->链接。
预处理
预处理用于将所有#include头文件以及宏定义替换成真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多
编译
这里的编译不是指从源文件到二进制程序的全部过程,而是将经过预处理之后的程序转换成特定汇编代码的过程。
汇编
汇编过程将上一步的汇编代码转换成机器码,这一步产生的文件叫做目标文件,是二进制。
链接
链接过程将多个目标文件以及所需要的的库文件(.so等)链接成最终的可执行文件。
C++是静态语言还是动态语言
所谓动态语言,就是类型检查是在运行的时候做的,变量使用之前不需要类型声明,通常变量的类型就是被赋值的那个值的类型,例如JavaScript等这种脚本语言就是动态语言,在编译阶段它不会判断代码是否符合规范,在运行的时候才会去判断。相反静态语言就是在编译阶段进行类型检查,当编译源程序的时候,出现不符合语法的规范,就会提示错误,在编译变量的数据类型即可确定,像Java、c、c++这种就属于静态语言。
全局变量、静态全局变量、静态局部变量和普通局部变量的区别
按存储区域分
全局变量、静态全局变量和静态局部变量都存放在内存的全局数据区;局部变量存放在内存的栈区。
按作用域分
全局变量在整个工程文件内都有效(可以使用extren可这个变量扩展过来)静态全局变量只在定义它的文件内有效静态局部变量只在定义它的函数内有效,且程序分配一次内存,函数返回后,该变量不会消失;局部变量在定义它 的函数内有效,但是函数返回后失效;全局变量和静态变量如果没有手动初始化,则编译器初始化为0.局部变量的值为不确定;静态局部变量和全局变量共享全局数据区,但静态局部变量只在定义它的函数中可见。静态局部变量与局部变量在存储位置上不同,使得其存在的时限也不同,导致这两者操作的运行结果也不同。
C++的多态类型
C++的多态类型分为两种,分别是:静态多态(重载,模板)、动态多态(覆盖,虚函数实现)
静态多态
在编译的时候,就确定调用函数的类型
动态多态
在运行的时候,才确定调用的是哪个函数,动态绑定。运行基类指针指向派生类的对象,并调用派生类的函数。
struct和class的区别
- C语言中的
struct表示结构 struct访问权限默认是public的,而class默认的访问权限是private的
简述进程和线程
- 进程与线程之间是父子关系。执行了一个可执行文件便会在系统中创建一个进程。而每个进程都有一个主线程和一个或者多个的子线程,一个进程里有且只有一个主线程。
- 而除主线程之外,我们可以通过自己的代码来创建多个子线程,我们每创建一个子线程就可以在同一时刻多干一件不同的事。
- 不过线程并不是越多越好,每创建一个子线程都需要一个独立的堆栈空间,线程之间的切换回需要保存很多的中间状态,这种状态间的切换会耗费本该属于程序运行的时间
线程的优缺点
优点:
- 线程启动速度更快,更轻量级
- 系统资源开销更少,执行速度更快
缺点:
- 使用起来有一定难度,需要小心处理数据的一致性问题。
malloc和new(区别)
new/delete是C++的关键字,而malloc/free是库函数,new/delete可以进行重载,而malloc/free不行;new时不需要指定空间大小,但是需要指定分配对象类型,返回的也是该类型的指针;而malloc时需要指定空间大小,无需指定数据类型,返回的是void *泛型指针;new失败时直接抛异常,而malloc则是返回NULL;new时会先调用malloc,然后调用所分配对象的构造函数进行构造;
指针和引用(区别)
- 引用必须被初始化,指针可以不初始化
- 引用不能改变被引用的对象,指针可以改变指向
- 引用没有自己独立的内存空间(指向变量内存),指针有自己独立的内存
- 引用不能为空,指针可以为空
什么时候用引用,什么时候用指针
对于使用传递的值而不做修改的函数
- 数据对象较小,如内置数据类型或小型结构体,则按值传递
void func(int );
- 数据对象是数组,则只能使用指针,并将指针const指针
void func(const int *,int);//第二个参数为数组长度
- 数据对象是较大的结构体,则const指针或const引用都行
struct struc{…};
void func(const struc *);
void func(const struc &);
- 数据对象是类,则使用const引用
void func(const string &,);
对于使用传递的值要做修改的函数
- 数据对象是内置数据类型,则使用指针
void func(int *);
- 数据对象是数组,则只能使用指针
void func(int *,int);//第二个参数为数组长度
- 数据对象是结构体,则使用引用或指针
struct struc{…};
void func(struc *);
void func(struc &);
- 数据对象是类,则使用引用
void func(ostream &);
指针常量和常量指针
指针常量:const修饰指针本身
常量指针(只读类型的指针):const修饰指针指向的类型
判断:const在*前还是后,前:常量指针;后:指针常量
指针常量:
- 必须初始化
- 可以通过指针修改指向变量的值
- 不可以改变指针的指向
常量指针:
- 可以不初始化
- 不可以通过指针修改指向变量的值
- 可以改变指针的指向
- 可以指向非const修饰的变量
左值引用和右值引用
首先要清楚左值和右值的概念。左值和右值的区分标准在于能够获取地址,能够获取地址便是左值,不能获取地址便是右值。
左值引用
传统的c++引用便是左值引用
int i = 1;
int &ii = i;
右值引用
c++11中增加了右值引用,右值引用关联到右值时,右值被存储到特定位置,右值引用指向该特定位置,也就是说,右值虽然无法获取地址,但是右值引用是可以获取地址的,该地址表示临时对象的存储位置。
int &&iii = 10;
右值引用可以解决两个问题:
- 临时对象非必要的昂贵的拷贝操作
- 在模板函数中如何按照参数的实际类型进行转发。