学科小知识扩充

1.static 和非static 的区别
局部变量:每次进入子函数都从新赋值,生命周期是子函数结束,内存就会被释放
static局部变量:开始定义时赋值,虽然它的做用域也只是子函数,可是它的生命周期倒是整个程序结束。html

static函数与普通函数的区别:
static函数在内存中只有一份,普通函数在每一个被调用中维持一份拷贝(堆栈),全局变量存在于(静态区)中,动态申请数据存在于(堆)中。
static全局变量和全局变量的区别:ios

全局变量的说明以前再加以static 就构成了静态的全局变量。全局变量自己就是静态存储方式,静态全局变量固然也是静态存储方式。这二者在存储方式上并没有不一样。区别在于非静态全局变量的做用域是整个源程序,当源程序有多个源程序构成时,其余源程序也能对非静态全局变量进行访问操做。可是静态全局变量则限制了它的做用域,让它只能在定义它的源程序里访问。c++

2.程序编译的基本流程
大体分为词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成五个阶段。
词法分析:检查单词合不合法,好比说中间有非法字符的话就不合法。
语法分析:检查程序在结构上合不合法,好比说少了一个分号之类的。知道有自顶向下(逐步推导)或自底向上(逐步归约)的分析方法。
语义分析:检查程序是否符合语言规范,好比说数组的下标是double型的话就会发生语义错误。
中间代码生成:中间代码其实就是一种结构简单,含义明确的记号系统
代码优化:代码优化其实就是在不改变结果的前提下,进行代码的等价交换。它主要在中间代码优化,可是在其余各个阶段也有起做用。
目标代码生成:目标代码多是机器代码也多是接近于机器语言的代码。程序员

3.TCP与UDP的区别,TCP如何保证链接的可靠性(三次握手)
速度上:UDP比TCP要快,实时
安全上:TCP比UDP安全,可靠
TCP是面上链接的,,UDP是无链接的。
TCP是面向字节流传输的,有序传输,防止了丢失和差错。UDP是面向报文,尽量不丢包,不保证顺序。
每一条TCP链接都是点对点的,UDP能够实现一对一,一对多,多对多的链接。
TCP因为头部比UDP的头部要长,因此资源消耗会比UDP多。web

TCP的三次握手保证了链接的可靠性:
第一次握手是,客户端发送报文给服务器,等待服务器肯定
第二次握手是,服务器接受到了客户端的消息,会回传一条报文给客户端,确认本身收到了报文
第三次握手是,客户端接收到了服务器的消息,而后回传确认的报文给服务器完成了三次握手。
四次挥手对应着断开TCP链接。
完整版:算法

在TCP/IP协议中,TCP协议提供可靠的链接服务,采用三次握手创建一个链接,如图1所示。

 (1) 第一次握手:创建链接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认。

 (2) 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时本身也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。

 (3) 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。



因为TCP链接是全双工的,所以每一个方向都必须单独进行关闭。
这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的链接。
收到一个 FIN只意味着这一方向上没有数据流动,一个TCP链接在收到一个FIN后仍能发送数据。
首先进行关闭的一方将执行主动关闭,而另外一方执行被动关闭。

(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。

(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN同样,一个FIN将占用一个序号。

(3)服务器B关闭与客户端A的链接,发送一个FIN给客户端A(报文段6)。

(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。

4.操做系统中的进程和线程的区别
1.进程在操做系统中可以独立运行,是资源分配的基本单位,拥有独自的资源,它表示的就是运行中的程序。
2线程是进程中的一个实例,能够说是轻量级的进程,是系统调度和分派的基本单位。
区别在于:
同一个进程中能够有多个线程,一个线程只能对应一个进程。
同一个进程下的全部线程都能共享这个进程的资源。
进程结束后线程就会被销毁。
线程执行时是同步和互斥的,好比说一个线程执行了一部分,可能资源就会被另外一个线程占用。编程

5.设计模式的七大原则设计模式

1.单一责任原则
核心:高内聚(模块内部的链接很紧密),低耦合(模块之间尽量地独立,少关联)
描述:每一个类尽量地实现单一的功能,若是把多个功能放在同一个类中,一个功能修改,可能会终止另一个功能,因此咱们要尽可能减小这种状况发生。

2.开-闭原则
核心:对扩展开放,对修改关闭
实现方法:
对不变的功能加以抽象成一个接口
遵循接口的最小功能原则
不足的部分用其余接口实现
模块之间的接口经过抽象接口进行
不断重构

3.里氏替换原则
核心:子类应当能够替代父类而且出如今全部父类能够出现的地方
描述:子类必须实现父类里面的全部方法,在类中调用的其余类必须是接口或者父类,否则就违背了该原则。子类的重载父类的方法时,输入条件必须与父类相等或者更多,这样调用的仍是父类的方法。子类容许本身的属性和方法。子类重载父类方法时能够缩小输出结果。

4.依赖倒置原则
核心:要依赖于抽象,不能依赖于具体的实现。
描述:高层模块不能依赖于低层模块,它们应该共同依赖于抽象(抽象类和接口)。抽象不该该依赖于细节,细节(具体实现)应该依赖于抽象。

5.接口隔离原则
核心:一个接口只提供一个对外的功能,不该该把全部的操做都封装在一个接口上。
描述:一个类对另外一个类的依赖性应该创建在最小接口上。
分离接口有两种方法:
委托分离接口:把请求委托给别的接口的实现类来完成所须要的职务,这就是适配器模式
多重继承分离接口:经过实现多个接口来实现所须要的职务

6.少继承多组合原则(合成复用)
核心:尽可能使用对象组合,而不是经过继承来实现复用。
描述:在一个新的对象里,使用一些旧的对象使它成为新对象的一部分。新对象经过向这些已有对象的委派来复用已有功能的目的。
复用的种类:
继承:优势在于实现起来比较容易,基类的大部分功能都会自动地流入派生类中,派生类也方便扩展或修改。缺点在于这样基类的实现细节就会暴露给派生类,这也被称做白箱操做。这样基类一旦改变就会影响到派生类。
合成聚合:优势在于新对象存取对象成分的惟一方法时经过成分对象的接口。这种复用也被成为黑箱操做,新对象不须要知道成分对象的内部实现,所须要的依赖较小,支持包装,能够动态修改,新对象能够把新的人物委派给合适的对象。

7.最少知识原则(迪米特法则)
核心:类间解耦,低耦合
描述:下降各个类之间的耦合,模块间的通讯经过接口来完成,而不用理会类内部的工做原理。
实现方法:
建立低耦合的类,下降类成员的访问权限,尽量设计为不变类,下降类的访问权限,对其余对象的引用降到最低,不应暴露类成员,应该提供相应的访问器。

6.进程之间的通讯方式(IPC):
管道,命名管道FIFO,消息队列,信号量,共享存储,Socket,Streams,其中Socket和Steams是支持两个不一样主机的进程通讯。
管道:半双工的通讯方式,只能单向流动,只容许亲缘进程之间的通讯,亲缘进程一般就是父子进程。
命名管道FIFO:半双工的通讯方式,可是容许无亲缘关系进程之间的通讯。
消息队列:就是消息的链表,存放在内核中,由消息队列标识符标识。
信号量:其实就是计数器,用来控制进程之间对共享资源的访问。
共享内存:多个进程共享同一片内存,实现消息的同步。
Socket:套接字,支持不一样机器之间的通讯
Steams:只能想到TCP通讯。数组

例子:
使用了【共享内存+信号量+消息队列】的组合来实现服务器进程与客户进程间的通讯。
共享内存用来传递数据;
消息队列用来 在客户端修改了共享内存后 通知服务器读取。
信号量用来同步;安全

7.A算法
A
是一个启发式搜索算法,从状态空间中对每个搜索位置进行评估,选出最优的位置,而后再继续评估,一直到终点。
广度搜索算法实际上是一种特殊的A算法,也是最烂的A,由于它的估值函数永远是0,没有任何启发性。
选出最小估价,能够用小根堆,在c++中用最小优先队列。
A*算法适合于网格地图。

8.c++虚函数的实现是经过虚表和虚指针,每一个类用一个虚表,虚表就记录了基类和派生类中虚函数的内存地址,每一个类的对象用一个虚指针。
做用:虚函数是用来实现多态的。声明virtual虚函数,用基类的指针,能够调用派生类的成员。也就是说基类指针能够按照基类的方式作事,也能够按照派生类的方式作事,呈现了多种表现形态,咱们称之为多态。
例子:注释的地方都是值得注意的

#include <iostream>
#include <string>
using namespace std;
class People
{
public:
	People(){}//必须有默认的构造参数
	People(string name,int age){
		m_name = name;
		m_age = age;
	}
	virtual void display(){
		cout << m_name << "的年龄为" << m_age<<endl;
	}
protected://声明的成员为保护类型
	string m_name;
	int m_age;
};
class Teacher:public People{//值得注意的是这里的不能漏掉public
public:
	Teacher(string name, int age, int salary){
		m_name = name;
		m_age = age;
		m_salary = salary;
	}
	virtual void display(){
		cout <<m_name<<"的年龄为"<<m_age<<"收入为"<<m_salary<<endl;
	}
private:
	int m_salary;
};
int main(){
	People *p = new People("xiaoming", 67);//声明一个基类指针
	p->display();//调用基类方法
	p = new Teacher("xiaohong", 67, 1000);//把基类指针指向派生类
	p->display();//调用派生类的方法
	system("pause");
	return 0;
}

9.c++的stl容器内部数据结构
vector:数组,元素不够时再从新分配内存,而后把元素拷贝到新数组中
deque(双向队列):数组
list:双向环状链表
slist:单向链表
stack:deque
queue:deque
map,set:红黑树
priority_queue(优先队列,能够作小根堆和大根堆):vector
unordered_map,unordered_set:hash表

10.平衡二叉搜索树
(二叉排序树,二叉搜索树,二叉查找树是同一个东西,左节点小于根节点,右节点大于根节点,键值是不能够重复的。)
定义:一棵空树或者是左右子树高度差的绝对值不超过1的树,而且左右子树也是一棵平衡二叉树,符合平衡条件又符合二叉搜索树条件的叫作平衡二叉搜索树。
红黑树:每一个节点都带有颜色属性的二叉搜索树。时间复杂度为log n,空间复杂度为 log n。
b树:b树容许有多个子女,从而减小了树的高度,b树的叶子节点所有出如今赞成层,并且都是没有关键字信息的,是一种多路平衡搜索树。
b+树:与b树不一样的是,b+树的叶子节点包含了全部关键字信息,以及指向关键字信息的指针,而后叶子节点自己是按照关键字信息从小到大链接起来的,全部的非终端节点均可以看成索引部分。

11.建堆的过程(以大根堆为例)
先用全部元素来构建出一个彻底二叉树,而后从最后一个非叶子节点开始调整。
先比较根,左孩子,若是左孩子比根大,则交换,交换后的两个节点都必须再次知足根节点最大的要求,不然又必须调整。
而后再比较右孩子,若是右孩子比根大,则交换,交换后的两个节点都必须再次知足根节点最大的要求,不然又必须调整。
直到树的根节点调整完就结束。

12.AB打包流程
http://www.360doc.com/content/17/0609/21/40005136_661467159.shtml
代码打包
https://blog.csdn.net/qq_18995513/article/details/51990523
Unity—AssetBundle的打包及四种加载资源方式
http://blog.sina.com.cn/s/blog_140bb6bd40102xajb.html
ab原理
http://www.xuanyusong.com/archives/2373

13.NGUI和UGUI的区别(后续补充)
NGUI是第三方开发的UI插件,而UGUI是unity内部的插件。
NGUI有本身的代码框架,而UGUI与日常的使用更接近。
NGUI有本身的图集须要维护,而UGUI则须要将图片类型改成Sprite(2D and UI),最后才会合成图集。
当UI须要与鼠标交互时,NGUI须要绑定colliders,可是UGUI不用。
NGUI支持图文混排,可是UGUI不行。
UGUI发展很快,而且能够实现更多的功能,能够取代NGUI原有的地位。

14.图论
1.在图中经常将数据元素称为顶点。
2.图是由顶点的有穷非空集合和顶点之间的边集合组成。
3.图中任意两个顶点之间的边是无向边,则该图为无向图,不然该图就是有向图。
4.简单图:不存在到自身的边,并且同一条边不能重复出现。
5.邻接点:有边的两个点叫作邻接点,同时称这条边依附于这两个点。有向图中,箭头指向的点能够称为另外一个点的邻接点。
6.有向边称为弧。
7.无向彻底图:任意两个顶点之间都存在边。含有n个顶点的无向彻底图有n*(n-1)/2条边。
有向彻底图:任意两个顶点之间都存在方向互为相反的两条弧。含有n个顶点的有向彻底图有n*(n-1)。
8.顶点的度:依附该顶点的边的个数。
在n个顶点,e条边的无向图中,度的个数为2e,入度和出度相等。
在n个顶点,e条弧的有向图中,该顶点为弧头的弧的个数为入度的个数,该顶点为弧尾的弧的个数为出度的个数。
9.在图中,权一般是指对边赋有意义的数值量。边上带有权的图叫作网。
10.路径上边的数目成为路径长度,第一个顶点和最后一个顶点相同的路径成为回路或者环。
11.简单路径:顶点不重复出现的路径。简单回路:除了第一个和最后一个顶点外,其余顶点不重复出现的回路叫作简单回路。
12.连通图:在无向图中,任意两个顶点之间都有路径(注意不是边)的图。
非连通图中的极大连通子图称为连通份量(即有多少个独立连通的小部分)。
13.强连通图:在有向图中,任意两个顶点之间都有路径,则称该有向图为强连通图。
非强连通图中的极大连通子图称为强连通份量。
14.深度优先遍历:访问顶点v,把v入栈,从v中未访问的邻接点中选择一个顶点w,把w入栈,再对w进行深度搜索,重复步骤,当一个顶点再也没有未访问的邻接点时则弹出栈,直到栈为空则中止。
广度优先遍历:访问顶点v,把v入队列,访问v的全部邻接点,把它们依次入队列,当一个队头顶点再也没有未访问的邻接点时就弹出队列,直到队列为空为止。
15.邻接矩阵:图的邻接矩阵储存也称为图的数组表示法,用一个一维数组储存顶点,而后用一个二维数组储存边的信息(各顶点间的邻接关系),显然无向图的邻接矩阵必定是对称矩阵。
16.邻接矩阵解决了的问题:
在无向图中,顶点i的度等于邻接矩阵的第i行或者第i列非零元素的个数。
在有向图中,顶点i的出度等于邻接矩阵第i行非零元素的个数。
要判断两个顶点是否有边,只须要判断数组元素值是否为1便可。
邻接矩阵和邻接表是图的两个经常使用的存储方法。
17.最小生成树:生成树上个边的权值之和称为生成树的代价,代价最小的生成树称为最小生成树。
最小生成树必须包括最小权值的边。
18.求最短路径算法:dijkstra算法(贪心算法的例子,每一个最短路径相加就成为了最终的最短路径)和floyd算法(动态规划)
dijkstra算法时间复杂度为:O(n^2),floyd算法时间复杂度为: O(n^3)。
19.用顶点表示活动,用弧来表示活动之间的优先关系,这样的有向图被称为AOV网
AOV网中没有入度的点叫作源点,没有出度的点叫作终点。
AOV网的两个性质:
只有进入该顶点的各活动都已经结束,该顶点所表明的事件才会发生。
只有在该顶点事件发生后,从该顶点出发的各活动才能开始。
具备最大路径长度的路径叫作关键路径,关键路径上的活动称为关键活动。
关键活动长度是整个工程所须要的最短工期,要缩短工期就必须加快关键活动。

15.UNET
UNET是unity自带的网络传输和管理集成组件,能够实现多人游戏的同步更新。
https://blog.csdn.net/qq_25601345/article/details/78551567?locationNum=8&fps=1

16.哈希表
原理:用一个下标范围比较大的数组来进行储存。而后设计一个散列函数,让每个元素关键字对应一个散列值。可是一个散列值极可能会对应着多个元素关键字,这时候就须要比较函数进行比较。尽管是这样,hash表也大大地提升了存储和查找的时间,而代价只是消耗了更多的内存。
在c++中,hash表并非标准的stl。

17.银行家算法
银行家算法是一种避免死锁的经典方法,它会事先判断进程所须要的资源会不会影响到整个系统的安全,若是安全则分配,不安全则不分配(不安全就是有可能发生死锁)。

18.mvc架构(model,view,controller)
mvc架构在unity的应用:mvc架构很是适合于UI的开发,UI界面至关于view,UI转换控制至关于controller,UI上的数据变换至关于model。

19.unity经常使用函数
https://blog.csdn.net/nobcaup/article/details/51502852

20.知道前序中序求后序,知道后序中序求前序。
例子:
原有序列:abcdef
前序:abdecf
中序:dbeafc
后序:debfca
怎么求后序呢,先从前序中得出a为根,而后a就把中序分红了两半,dbe为左子树的中序遍历,fc为右子树的中序遍历,但咱们还不知道它们的顺序。同时咱们能够从前序中找出这两半,bde为左子树的前序遍历,cf为右子树的前序遍历。
若是只看中序遍历咱们是看不出来的原序列的,特别是大量数据的时候。
因此咱们必须结合前序来进行判断,这样又变成了一个子问题,若是用编程来实现的话更方便一些。
可是若是是选择题的话,咱们必须本身找出来,首先从简单的右子树开始,前序cf,中序fc,这就说明了c是根,f为左孩子节点。
而后再到左子树前序bde,中序dbe,容易看出b为根节点,d为左孩子节点,e为右孩子节点。
若是数据比较多的时候咱们就不能一眼看出了,咱们必须按照一开始的方法划分。知道了原有序列,得出后序就很简单了。
若是知道后序和中序也是同样的。
可是知道前序和后序该是如何呢,这个我百度过,没有得出结论,可是若是是选择题的话,咱们可使用目测法。(但不保证数据多的时候能用)
前序:abdecf
后序:debfca
仔细观察,除去a之外,bde和deb的位置是相互变更的,而后,cf和fc也是相互变更的,(变更的位置不会超出它们的范围则把它们分为一组)咱们能够把它们分开。
而后就能逐步推断出原序列了。

21.new、delete、malloc、free关系
new和delete对应,是c++的运算符。malloc和free对应,是c&c++的标准库函数,它们都有动态申请内存和清理内存的做用。可是对于非内部对象时,对象建立的同时要自动执行构造函数,在对象销毁以前要自动调用析构函数。因为malloc和free是库函数,咱们不能把调用构造函数和析构函数的任务强加与它们,因此c++出现了两个新的运算符new/delete来执行这个任务。

22.delete与 delete []区别
delete与new配套,delete []与new []配套,delete只会调用一次析构函数,而delete[]会调用每个成员的析构函数。

23.基类和子类的构造函数和析构函数关系:
定义一个对象时先调用的是父类的构造函数,再调用子类的构造函数。
销毁一个对象时先调用的时子类的析构函数,再调用父类的析构函数。

24.多态:对于不一样的对象接受相同的信息有不一样的活动。
多态性:程序的运行时的多态性是经过继承和虚函数来来体现。
虚函数:在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。容许在派生类中对基类的虚函数从新定义。
纯虚函数的做用:在基类中为其派生类保留一个函数的名字,以便派生类根据须要对它进行定义。做为接口而存在 纯虚函数不具有函数的功能,通常不能直接被调用。
纯虚函数的定义:virtual <类型><函数名>(<参数表>)=0;
从基类继承来的纯虚函数,在派生类中还是虚函数。若是一个类中至少有一个纯虚函数,那么这个类要声明为抽象类(abstract class)。
抽象类中不只包括纯虚函数,也可包括虚函数。抽象类必须用做派生其余类的基类,而不能用于直接建立对象实例。但仍可以使用指向抽象类的指针支持运行时多态性。
(重载与多态无关)

25.什么是“引用”?申明和使用“引用”要注意哪些问题?
引用就是某个目标变量的“别名”(alias),对应用的操做与对变量直接操做效果彻底相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,至关于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名做为其余变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它自己不是一种数据类型,所以引用自己不占存储单元,系统也不给引用分配存储单元。不能创建数组的引用。

26.将“引用”做为函数参数有哪些特色?
(1)传递引用给函数与传递指针的效果是同样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,因此在被调函数中对形参变量的操做就是对其相应的目标对象(在主调函数中)的操做。
(2)使用引用传递函数的参数,在内存中并无产生实参的副本,它是直接对实参操做;而使用通常变量传递函数的参数,当发生函数调用时,须要给形参分配存储单元,形参变量是实参变量的副本;若是传递的是对象,还将调用拷贝构造函数。所以,当参数传递的数据较大时,用引用比用通常变量传递参数的效率和所占空间都好。
(3)使用指针做为函数的参数虽然也能达到与使用引用的效果,可是,在被调函数中一样要给形参分配存储单元,且须要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另外一方面,在主调函数的调用点处,必须用变量的地址做为实参。而引用更容易使用,更清晰。

27.在何时须要使用“常引用”? 
若是既要利用引用提升程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;

例1

int a ;
const int &ra=a;
ra=1; //错误
a=1; //正确

例2
string foo( );
void bar(string & s);
那么下面的表达式将是非法的:
bar(foo( ));
bar(“hello world”);
缘由在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。所以上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。引用型参数应该在能被定义为const的状况下,尽可能定义为const 。

28.将“引用”做为函数返回值类型的格式、好处和须要遵照的规则?(转发,有待研究)

格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }

好处:在内存中不产生被返回值的副本;(注意:正是由于这点缘由,因此返回一个局部变量的引用是不可取的。由于随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

注意事项:
(1)不能返回局部变量的引用。这条能够参照Effective C++[1]的Item 31。主要缘由是局部变量会在函数返回后被销毁,所以被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
(2)不能返回函数内部new分配的内存的引用。这条能够参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种状况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是做为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就没法释放,形成memory leak。
(3)能够返回类成员的引用,但最好是const。这条原则能够参照Effective C++[1]的Item 30。主要缘由是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值经常与某些其它属性或者对象的状态有关,所以有必要将赋值操做封装在一个业务规则当中。若是其它对象能够得到该属性的很是量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
(4)流操做符重载返回值申明为“引用”的做用:
流操做符<<和>>,这两个操做符经常但愿被连续使用,例如:cout << “hello” << endl; 所以这两个操做符的返回值应该是一个仍然支持这两个操做符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。可是对于返回一个流对象,程序必须从新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操做符其实是针对不一样对象的!这没法让人接受。对于返回一个流指针则不能连续使用<<操做符。所以,返回一个流对象引用是唯一选择。这个惟一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的缘由吧。
赋值操做符=。这个操做符象流操做符同样,是能够连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操做符的返回值必须是一个左值,以即可以被继续赋值。所以引用成了这个操做符的唯一返回值选择。

#include<iostream.h>

int &put(int n);

int vals[10];

int error=-1;

void main()

{

put(0)=10; //以put(0)函数值做为左值,等价于vals[0]=10; 

put(9)=20; //以put(9)函数值做为左值,等价于vals[9]=20; 

cout<<vals[0]; 

cout<<vals[9];

} 

int &put(int n)

{

if (n>=0 && n<=9 ) return vals[n]; 

else { cout<<"subscript error"; return error; }

}

(5)在另外的一些操做符中,却千万不能返回引用:±*/ 四则运算符。它们不能返回引用,Effective C++[1]的Item23详细的讨论了这个问题。主要缘由是这四个操做符没有side effect,所以,它们必须构造一个对象做为返回值,可选的方案包括:返回一个对象、返回一个局部变量的引用,返回一个new分配的对象的引用、返回一个静态对象引用。根据前面提到的引用做为返回值的三个规则,二、3两个方案都被否决了。静态对象的引用又由于((a+b) == (c+d))会永远为true而致使错误。因此可选的只剩下返回一个对象了。

29.结构体与联合有和区别?
(1). 结构体和联合都是由多个不一样的数据类型成员组成, 联合中全部成员共用一块地址空间的, 而结构体的不一样成员的存放地址不一样。
(2). 对于联合的不一样成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构中的不一样成员赋值是互不影响的。

30.重定义redefining
  派生类对基类的成员函数从新定义,即派生类定义了某个函数,该函数的名字与基类中函数名字同样。
  重定义也叫作隐藏,子类重定义父类中有相同名称的非虚函数(参数能够不一样)。若是一个类,存在和父类相同的函数,那么这个类将会覆盖其父类的方法,除非你在调用的时候,强制转换为父类类型,不然试图对子类和父类作相似重载的调用时不能成功的。
重定义须要注意:
不在同一个做用域(分别位于基类、派生类)
函数的名字必须相同
对函数的返回值、形参列表无要求
若派生类定义该函数与基类的成员函数彻底同样(返回值、形参列表均相同),且基类的该函数为virtual,则属于派生类重写基类的虚函数
若从新定义了基类中的一个重载函数,则在派生类中,基类中该名字函数(即其余全部重载版本)都会被自动隐藏,包括同名的虚函数

31.C++是否是类型安全的?
答案:不是。两个不一样类型的指针之间能够强制转换(用reinterpret cast)。C#是类型安全的。
main 函数执行之前,还会执行什么代码?
答案:全局对象的构造函数会在main 函数以前执行。

32.描述内存分配方式以及它们的区别?(特别注意)
1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。(记住静态就是在静态存储区的,无论是局部仍是全局)

2) 在栈上建立。在执行函数时,函数内局部变量都是在栈上建立,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。

3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员本身负责在什么时候用free 或delete 释放内存。动态内存的生存期由程序员决定,使用很是灵活,但问题也最多。

分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

BOOL : if ( !a ) or if(a)

int : if ( a == 0)

float::if ( a < 0.000001 && a >-0.000001)

pointer : if ( a != NULL) or if(a == NULL)

33.虚继承的做用:虚继承:多个派生类保存相同基类的同名成员时,虽能够在不一样的数据成员中分别存放不一样的数据 ,但咱们只须要相同的一份。解决了多父类重复成员只保留一份的问题。
举个例子,有一张沙发床。它继承于沙发类,也继承于床类。
可是它们都继承于家具类,实质上咱们只须要一个家具类属性(包含长宽高),可是若是分别继承则会产生两个不一样的属性,这时咱们就必须用虚继承了。
当床和沙发都虚继承于家具类时,它们便公用了同一个家具属性。
子类沙发床继承于沙发和床也是共用这套属性。

34.请说出const与#define 相比,有何优势?
const做用:定义常量、修饰函数参数、修饰函数返回值三个做用。被Const修饰的东西都受到强制保护,能够预防意外的变更,能提升程序的健壮性。
1) const 常量有数据类型,而宏常量没有数据类型。编译器能够对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,而且在字符替换可能会产生意料不到的错误。(#define没有安全检查,无类型,知识字符替换)
2) 有些集成化的调试工具能够对const 常量进行调试,可是不能对宏常量进行调试。

35.int (*s[10])(int) 表示的是什么?
int (*s[10])(int) 函数指针数组,每一个指针指向一个int func(int param)的函数。

36.引用与指针有什么区别?

  1. 引用必须被初始化,指针没必要。
  2. 引用初始化之后不能被改变,指针能够改变所指的对象。
  3. 不存在指向空值的引用,可是存在指向空值的指针。

37.基类的析构函数不是虚函数,会带来什么问题?
派生类的析构函数用不上,会形成资源的泄漏。

38.构造函数不能声明为虚函数

  1. 对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
    答 、c用宏定义,c++用inline

40.函数指针和指针函数的区别?
函数指针是指向一个函数入口的指针;
指针函数是函数的返回值是一个指针类型。

41.指针的几种典型应用状况?

答:
int *p[n];—–指针数组,每一个元素均为指向整型数据的指针。

int (*)p[n];—p为指向一维数组的指针,这个一维数组有n个整型数据。

int *p();——函数带回指针,指针指向返回的值。

int (*)p();—-p为指向函数的指针。

42.unordered_map,unordered_set,map和set的用法和区别
unordered_map和unordered_set内部是无序的,它们是基于hash表的,map和set是有序的,基于红黑树。
unordered_set和set能够用于存储无重复数,只能够经过迭代器访问
unordered_map和map用来存储键值对,一一对应,能够经过下标访问。
都有find方法,获得的对象是一个iterator。
set用insert方法进行插入,map能够用下标进行插入,也能够经过insert方法来进行访问mymap.insert(make_pair(“c++”,100))。
都用erase方法来删除数据。

43.const的一些用法:
const是C语言的一种关键字,起受保护,防止之外的变更的做用!能够修饰变量,参数,返回值,甚至函数体。const能够提升程序的健壮性,你只管用到你想用的任何地方。
注意: 若是用const来修饰成员函数的话,是不能修改为员变量的。
若是参数或者返回值是值类型的话,使用const没有意义。
http://www.cppblog.com/xczhang/archive/2008/01/13/41092.html

const和define的区别:

  1. 编译器处理方式不一样   define宏是在预处理阶段展开。   const常量是编译运行阶段使用。 (2) 类型和安全检查不一样   define宏没有类型,不作任何类型检查,仅仅是展开,可能会有未知错误。   const常量有具体的类型,在编译阶段会执行类型检查。 (3) 存储方式不一样   define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。   const常量会在内存中分配(能够是堆中也能够是栈中)。