指针和引用的区别
- 指针指向一块内存,它的内容是指向内存的地址;引用是某内存的别名。
- 引用使用时无需解引用;指针则需要解引用。
- 引用不能为空,指针可以为空。
- 引用在定义时被初始化一次,之后不可再改变;指针可变。
- 程序为指针变量分配内存区域,而引用不需要分配内存区域。
memcpy和strcpy的区别
memcpy用来进行内存拷贝,有指定的拷贝数据长度,可拷贝任何数据类型的对象。strcpy只能拷贝字符串,遇到’\0’结束拷贝。
new和malloc,free与delete的区别
- malloc与free是c/c++的标准库函数,new和delete是c++的运算符。
- 对于非内部数据类型的对象而言,只使用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之要自动执行析构函数。由于malloc/free是库函数而非运算符,不在编译器控制权限之内,不能把执行构造函数和析构函数的任务强加于malloc和free。
- 关于new和malloc申请到的内存,new会执行默认初始化(对于内置类型,数值是不确定的);malloc申请到的则是一段空间,需要自己强制转换为需要的类型。二者均需要手动赋值,所不同的在于new可以在申请内置类型内存时在类型后面加上()指定清0。
struct和class的区别
- struct默认情况下成员是public的,class默认情况下成员是private的。
- struct保证成员按照声明顺序在内存中存储;class不保证。
- struct默认的继承是public的,class则是private。
struct和union
- union类型变量,所有成员变量共享一块内存,该内存大小由这些成员变量中长度最大的一个来决定,struct中成员变量内存都是独立的。
- union分配的内存是连续的,而struct不能保证分配的内存是连续的。
全局变量
- 全局变量可被多个.c文件定义,但必须用static来修饰,也就是将全局变量的作用域限定在文件中。
- 可以在不同的文件中声明同名的全局变量,但只能有一处赋初值操作。
全局对象的构造函数会在main函数之前执行
内存分配方式
- 从静态存储区域分配,内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
- 从栈上分配,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
- 从堆上分配,即动态内存分配。程序在运行的时候用malloc或new申请,然后用free或delete释放。
类成员函数重载、覆盖和隐藏区别
- 成员函数被重载,必须有以下特征:
- 相同的范围(在一个类中)
- 函数名字相同
- 参数不同
- virtual关键字可有可无
- 重写(即实现了多态)指派生类函数覆盖基类函数
- 位于不同的范围(分别位于派生类与基类)
- 函数名字相同
- 参数相同
- 基类必须有virtual关键字
- 函数原型理应完全一致,但有特例,即基类用virtual申明的函数返回值是对本身的引用或指针;派生类用来重写基类函数的那个函数返回对派生类本身的引用或指针。如 Base* Base::copy(Base*)
Derived* Derived::copy(Base*)
- ”隐藏“是指派生类的函数屏蔽了其从基类继承而来的同名函数。
- 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论
有无virtual关键字,基类的函数都将被隐藏(注意与重载的区别) - 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数将被隐藏(注意与重写的区别)。
- 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论
static的用途
- 限制变量的作用域
- 设置变量的存储域
const和#define
- const申明的变量有数据类型;而宏没有数据类型。编译器可以对前者进行类型安全检查,对后者只进行字符替换,没有类型安全检查,在字符替换过程中可能会产生意想不到的错误。
构造函数不能被声明为虚函数
内联函数也不能被声明为虚函数
进程间通信方式
- 管道(有名管道,无名管道)
- 共享内存
- 消息队列
- 信号量
- socket通信
线程同步方式
- 临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
- 互斥量:为协调多线程对一个共享资源的单独访问而设计。
- 信号量:为了控制一个具有有限数量用户资源而设计。
- 事件:用来通知线程有些事件已发生。
进程和线程的区别
- 进程是拥有资源的一个独立单位,线程是不拥有资源的。
- 线程作为调度和分配的基本单位,进程是作为资源的基本单位。
- 进程可以并发执行,同一个进程中的多个线程是可以并发执行。
- 进程在创建和销毁的时候,由于系统要分配和回收资源,导致系统的开销明显大于线程。
- 一个进程可以拥有多个线程。
- 子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
- 相当于进程而言,线程是一个更加接近于执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
虚函数和纯虚函数
- 虚函数必须在声明的类里被实现,纯虚函数则没有实现。
- 虚函数可以在子类中不被重写,但是纯虚函数必须在子类中重写。
- 动态内存分配时,析构函数必须是虚函数,但没有必要是纯虚函数。
刷新缓冲区
- 换行
- fflush
- 程序结束
必须使用成员初始化列表的情况
- 存在引用成员
- 存在const修饰的成员
- 存在继承自基类的构造函数
c++中4种类型转换方式
c语言方式的强制类型转换过于粗暴,难于定位所有使用强制类型转换的语句。
- static_cast
- dynamic_cast
- const_cast
- reinterpret_cast
main函数在执行完毕后,还能再执行一段代码吗
可以用_onexit或atexit函数注册一个函数,在主函数执行完毕后,执行注册的函数。
如何判断一段程序是由C编译还是由C++编译?
#ifndef __cplusplus
cout<<“C++”;
#else
cout<<“C”;
#endif
字节对齐
- 当结构体内不存在大于处理器位数的元素时,结构体以最大元素长度的整数倍对齐。
- 对同一个数据类型(short、int、long)发生了跨段分布,(在32位机里,即一个数据类型分布在两个段中)才会发生字节对齐。
c++为什么用模板类
- 可用来创建动态增长和减小的数据结构
- 是类型无关的,因此具有很高的可复用性
- 在编译时而不是运行时检查数据类型,保证了类型安全
- 是平台无关的,具备可移植性
- 可用于基本数据类型
使用线程如何防止出现大的波峰
为了防止同时产生大量的线程,使用线程池,可同时提高调度效率和限制资源使用,线程池中的线程达到最大数时,其他线程就会排队等待。
TCP/IP建立连接的过程
- 建立连接时,客户端发送syn(syn = j)分节到服务器,并进入SYN_SEND状态,等待服务器确认。
- 服务器收到syn包,必须确认客户的syn(ack = j + 1),同时自己也发送一个syn(syn = k)分节,即SYN+ACK包,此时服务器进入SYN_RECV状态。
- 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack = k+ 1)
- 客户端进入ESHABLISHED状态,待确认包到达服务器后,服务器也进入ESHABLISHED状态,完成了三次握手。
不允许重载的5个运算符
- .*
- ::
- sizeof
- ?:
- .
构造函数和析构函数的调用顺序,析构函数为什么设定为virtual
构造函数的调用顺序:
基类构造-对象成员构造-派生类构造
析构函数与构造函数顺序正好相反,析构函数设定为虚拟的,是为了防止析构不彻底,造成内存泄露。
c++是不是类型安全的?
不是,两个不同类型的指针之间可以强制转换(reinterpret_cast)
宏
定义一个宏时,定义的每个形参和整个表达式都必须用括号括起来,以避免不可预料的错误发生。
多态的两个必要条件
- 基类的指针或引用指向一个派生类对象
- 虚函数