解:消息就是在事件驱动模式下,事件发布函数和具体功能执行函数(或者代码段)之间的调用协议,调用协议的执行表现为窗口事件发布函数跟具体功能执行函数(或者代码段)之间的选择关系。在Windows系统下(下面所述均为Windows系统),对计算机外设的操作,例如当用户敲击键盘键、点击鼠标、热插拔USB盘等,系统都认为外设发生了事件,于是系统调用专职函数就把这些事件进行收集,形成现场信息,赋值给一个叫做“消息结构体”的对象,那么这个被赋予特定意义的消息结构体对象就可以称之为“消息”;然后,专职函数再把这个“消息”投递到(Post)到系统中一个专职消息管理的机构中去,这个过程就完成了消息形成和投递。可以这样想象这个所谓的“消息管理机构”的主要运作:
解:Windows中的进程简单地说就是一个内存中的可执行程序, 提供程序运行的各种资源. 进程拥有虚拟的地址空间, 可执行代码, 数据, 对象句柄集, 环境变量, 基础优先级, 以及最大最小工作集. Windows中的线程是系统处理机调度的基本单位. 线程可以执行进程中的任意代码, 包括正在被其他线程执行的代码. 进程中的所有线程共享进程的虚拟地址空间和系统资源. 每个线程拥有自己的例外处理过程, 一个调度优先级以及线程上下文数据结构. 线程上下文数据结构包含寄存器值, 核心堆栈, 用户堆栈和线程环境块.
进程的虚拟地址空间,首先可以把"虚拟"这个词拿掉, 对于简化进程模型有很大帮助(当对进程/线程和虚拟内存部分都充分理解后, 那时结合起来再考量会有更深程度的掌握). 地址空间就是系统给予进程的, 进程内任何可执行代码都可以感知的内存区域.(注意, 这里用了"感知"一词而不是访问, 其中的原因可以在后面讲解中找到) 问题: 地址空间有多大? 基地址和最大地址是什么?系统寻址能力决定了地址空间的大小. 主流的Windows系统是32位系统, 寻址能力是32位(形象的说就是指针是32位的), 所以地址空间的大小是4GB. 地址空间的基地址为0x00000000, 最大地址是0xFFFFFFFF. 4GB的地址空间被划分为2个大的内存区域, 用户区和系统区.
进程和线程的关系 -- 进程是容器:每个windows进程开始于它的被默认创建的第一个线程, 通常称其为主线程. 这种机制暗示了一个事实: 进程含有至少一个线程. 主线程和其它的线程没有任何区别, 每个线程都可以创建新的线程. 进程中所有线程都结束时进程会自动被结束, 而主动结束进程时, 如果还有线程没完成, 则系统自动结束这些线程.在windows中, 进程不再是处理机资源分配的最小单位, 那么它还是一个动态的实体吗? 是的, 从多进程并发的角度来看, 进程仍然是一个动态的实体, 但它的动态是它的线程的动态特征的抽象. 举个例子, 一个进程含有3个线程, 那么当3个线程都阻塞时, 进程表现为阻塞. 但只要有一个线程是就绪态, 哪怕其它2个线程是阻塞态, 进程仍然表现为就绪. 从线程的角度看, 进程表现的更像一个容器, 它代表线程接受分配到的资源(除处理机资源), 为线程提供主体(执行代码+数据), 自己却没有运行的概念. 此时, 进程是静态的实体.
解:术语“32 位”和“64 位”是指计算机的处理器(也称为“CPU”)处理信息的方式。64 位版本的Windows 可处理大量的随机存取内存 (RAM),其效率远远高于 32 位的系统。64bit计算主要有两大优点:可以进行更大范围的整数运算;可以支持更大的内存。不能因为数字上的变化,而简单的认为64bit处理器的性能是 32bit处理器性能的两倍。实际上在32bit应用下,32bit处理器的性能甚至会更强,即使是64bit处理器,目前情况下也是在32bit应用下性能更强。所以要认清64bit处理器的优势,但不可迷信64bit。
内存这是64位系统最显著的优点,它可以使用超过4GB的内存 。大多数新的台式机和笔记本电脑至少拥有4GB的内存。问题是,像Vista和Win 7的32位版本只能够用大约3GB的内存 。相比之下,64位的Windows 不仅可以利用高达192GB的内存,还能够使用的内存映射取代BIOS的功能,从而使操作系统真正使用完整的4GB的。因此,如果您安装Win7 x64,对于有的4GB内存的机器你不会浪费1GB内存。
解:我们都知道,c++为了与c语言能够兼容,c++做出了很大的牺牲,包括保留了struct关键字,还有编译期间添加了好多隐藏的代码。但是虚函数却不能与c语言实现兼容。而且有了虚函数,类的数据对象布局都发生了巨大的变化。这些暂时不说,还是回到上面的问题吧!我们都知道函数可以分为三种,一种是类的成员函数(member function),又可分为非静态成员函数(non-static member function),以及静态成员函数(static member function),而还有一种非类的成员函数(non-member function)。在类的非静态成员函数中又可以分为普通的函数以及虚函数。根据这种函数的分类,就知道了函数绝对是不能同时为虚函数以及静态成员函数的。对虚函数还可以继续细分,一是纯虚函数,一种就是普通的虚函数。纯虚函数必须在普通的虚函数基础上加上“=0”,同时普通的虚函数必须要有函数的实现。而纯虚函数默认情况是只有定义,而无需实现的,即只是定义一个接口(当然也可以实现,这时实现认为是默认的一种状态显示),同时包含了纯虚函数的类表明该类时一个抽象类,不能定义该类的对象,也就是说该类被定义成基类,是要被继承的,通过继承类来完成基类对象的生成。最后,强调一下,虚函数必须有一个关键字来修饰:virtual ,同时不能有static修饰。
虚函数的作用?我们知道面向对象语言的意义是让程序用一种符合人的思维来运行,而虚函数在c++面向对象语言的实现中起着举足轻重的作用。简而言之,虚函数的作用就是实现“动态联编”,也就是在程序的运行阶段动态地选择合适的成员函数。具体的实现方式是:在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。编译器在编译过程中发现类的函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数,具体的实现机制下篇再讲。
这里提前说一下,类的静态成员函数与非类的成员函数对于类对象来说,访问函数的效率相当,都是在编译器确定,而虚函数需要在运行期确定,所以效率较低(符合上帝是公平的规律吧)。虚函数的使用?正确的使用虚函数是一个比较简单的问题。要实现动态联编,即只能用一个基类的指针或者引用来指向派生类对象,为什么必须要这样,见后面的虚函数实现机制。而把派生类对象赋值或者拷贝给基类的对象,只能实现派生类隐式转换成基类,即在编译器完成了派生类的截断,不能达到动态联编得作用。
解:static关键字是C, C++中都存在的关键字。static从字面理解,是“静态的“的 意思,与此相对应的,应该是“动态的“。static的作用主要有以下3个:
1、扩展生存期
这一点主要是针对普通局部变量和static局部变量来说的。声明为static的局部变量的生存期不再是当前作用域,而是整个程序的生存期。在程序中,常用内存类型主要有堆、栈和静态存储区。要理解static局部变量就必须首先理解这三种内存类型。在C/C++中, 局部变量按照存储形式可分为三种auto, static, register
2、限制作用域
这一点相对于普通全局变量和static全局变量来说的。对于全局变量而言,不论是普通全局 变量还是static全局变量,其存储区都是静态存储区,因此在内存分配上没有什么区别。区别在于:
3、数据唯一性
这是C++对static关键字的重用。主要指静态数据成员/成员函数。表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员.在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性.这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )
static数据成员的初始化:1) 初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆。2) 初始化时不加该成员的访问权限控制符private,public等。3) 初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。4) 静态数据成员是静态存储的,它是静态生存期,必须对它进行初始化。
Static成员函数:静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。静态成员函数仅能访问静态的数据成员,不能访问非静态的数据成员,也不能访问非静态的成员函数,这是由于静态的成员函数没有this指针。
解:牛顿迭代
#include<iostream> using namespace std; int main() { int N; cout<<"输入N的值:"; cin>>N double x1 = 1; double x2 = x1/2.0+N/2.0/x1; while( fabs(x2-x1)>0.001) { x1 = x2; x2 = x1/2.0+N/2.0/x1; } cout<<x1<<endl; return 0; }
解:
ab┗━━━━┳━━┻━━━━━━━┻━━━━┳━━┻━━━━━━━┻ ┅ ┅ ┅ ┻━━━━┳━━┻━━━━━━━┻━━━━┳━━┻━━━━━━━┛
上图表示7点-8点之间的60分钟区间内, a、b两人可用的乘车时间点(a上b下)
可以看出每10分钟有一个最小循环, 那么可以先就前10分钟的区间进行分析.
以b为主体, b的时间可以被各时间点切成三份 (30−3,23−5,55−10) , 那么在这个区间里, 两人相遇的概率是
360×30−360+260×130−1360+560×85−1360=753600
需要注意的是后两项"使用了"下一个循环区间的时间, 因此需要单独考虑最后10分钟的相遇概率
360×350−5360+260×1050−6060+560×555−6060=543600
汇总的相遇概率为
753600×5+543600=1431200
解:
转移矩阵为
A=(0.70.50.30.5)
P(周三有雨|周一有雨)=[(1 0)A2]1,1=[(0.7 0.3)(0.70.50.30.5)]1,1=0.64解:首先,平均等待时间即为等待时间的期望,倘若依照题意,发车间隔并不固定又如何呢?
发车间隔不固定,那么 tA,tB 的值域变为 [0,+∞) ,随之而来的是另一个问题,概率密度分布是什么样的?此时值域不再有限,无法使用均等分布。注意这里问题的关键字是等待,说起等待,首先就应该想到泊松分布(Poisson Distribution)和泊松过程(Poisson process)。这里,等车的过程就可以看作两个相互独立的泊松过程。泊松过程的平稳独立增量假设十分重要,这意味着从任意时刻开始分布都是一样的,也就是说并不存在等待越久公车更可能即将到来这件事情。由此,泊松过程中,两次事件中的间隔时间服从指数分布,即
平均间隔时间即期望间隔时间 E[t]=∫+∞0tλe−λt dt=1λ (1)
由这个结论加上已知可得 tA∼15 e−15tA,tA⩾0; tB∼110 e−110tB,tB⩾0
那么仍然根据独立假设,可得 p(tA,tB)=15e−15tA110e−110tB, tA⩾0, tB⩾0
此时积分有
E[t]=∫+∞0∫+∞tBtB15e−15tA110e−110tB dtA dtB+∫+∞0∫+∞tAtA15e−15tA110e−110tB dtB dtA
=∫+∞0tB110e−110tBe−15tB dtB+∫+∞0tA15e−15tAe−110tA dtA
=∫+∞0x(15+110) e−(15+110)x dx
=115+110
=313