MFC常见⾯试问题(持续更新)
1)说说mfc中的类继承图的基本框架,
MFC的类层次(
) MFC(微软基础类)也是⼀种应⽤程序框架,定义了应⽤程序的⼀般处理流程,⽤于对Windows API实现基于⾯向对象技术的封装,隐藏在Windows下使⽤C++编程的⼤量内部细节。在开发应⽤程序的过程中,编程⼈员可以通过对类库中已有类的继承,⽣成功能更加强⼤的类库以供⾃⼰所⽤。 在MFC中类的层次结构(即继承关系)如图5-3所⽰。 从图中可知,在MFC中⼤多数的类都派⽣于CObject类,它的主要作⽤是为⼦类提供⼀些基本的功能,这些派⽣类构成了MFC应⽤程序的基本框架,它们各⾃的功能
描述如表5-1所⽰。 派⽣类 功能描述 CCmdTarget ⽤于处理⽤户请求 CWinThread 代表应⽤程序内部的执⾏线程 CWinApp 应⽤程序的核⼼ CWnd 为所有的窗⼝类提供基本的功能,处理常见的系统消息 CView ⽤于显⽰数据并与⽂档对象进⾏交互 CFrameWnd 应⽤程序的主框架 CDocument 包含应⽤程序的数据集 下⾯将对上述表中各个类的功能进⾏具体的讲解。 1)CCmdTarget类 CCmdTarget类是MFC的消息映射基础类,MFC为该类设计了许多的成员变量及函数以解决消息映射的问题。派⽣于CCmdTarget的类可⽤于处理当⽤户选择菜单或单击按钮等操作时所产⽣的Command消息。 在实际的开发过程中,我们通常很少直接从CCmdTarget中派⽣类。当想要⽣成⼀个处理按键消息的类时,只需从继承于CCmdTarget类的框架⼦类CView、CWinApp、CDocument、CWnd和CFrameWnd中选择⼀个来充当⽗类即可。
2)CWinThread类 CWinThread类是MFC中⽤于封装线程的类,它的成员函数可以使MFC应⽤程序创建和管理包括UI及⼯作者在内的线程。每个MFC应⽤程序都⾄少应该使⽤⼀个从CWinThread派⽣的类,应⽤程序类CWinApp就是⼀个代表。 3)CWinApp类 CWinApp 类通常代表应⽤程序⾃⼰,它封装了应⽤程序的初始化、运⾏及终⽌的过程。基于框架的应⽤程序必须有且仅有⼀个派⽣于CWinApp的类的对象,并在完成窗⼝的创建⼯作之前执⾏对该对象的构造。 应⽤程序类的对象需要完成以下⼯作。 初始化应⽤程序。 建⽴⽂档模板结构。 循环检索消息队列中的消息并将这些消息发送到指定的地⽅。 执⾏应⽤程序退出时的清理⼯作。 4)CDocument类 CDocument类是在使⽤⽂档/视图结构的
应⽤程序中⽂档对象的基类,它为应⽤程序的⽂档对象提供了基本的功能,包括新建、串⾏化数据等。
5)CWnd类 CWnd类是所有MFC 窗⼝的基类,它封装了窗⼝的基本操作,包括窗⼝的创建、销毁、设置窗⼝风格等,以及窗⼝对⼤部分消息的默认响应。开发⼈员可以直接从CWnd派⽣其他类,但通常情况下我们并不这么做,⽽是通过继承CWnd的派⽣类⽣成新类。
6)CFrameWnd类 CFrameWnd类往往⽤于创建应⽤程序的主窗⼝,并定义了⼤量管理视图和⽂档对象的成员函数及变量。在编写⽂档/视图结构的应⽤程序时,视图对象等将作为CFrameWnd的⼦窗⼝实现对客户区的共享,并被CFrameWnd有序排列。 7)CView类CView类是在使⽤⽂档/视图结构的应⽤程序中视图对象的基类,它是⽤户的主要操作界⾯。在应⽤程序中,⼀个视图对象通常只对应⼀个⽂档对象,但⼀个⽂档对象却可以关联多个视图对象,并且每个视图对象都以不同的形式来显⽰⽂档中的数据。 在上述CObject类的派⽣类中,CWinApp类、CDocument类、 CCmdTarget类及CWinThread类构成了应⽤程序的结构类,代表了应⽤程序的基本结构元素。换句话说,当⼀个应⽤程序开始运⾏时,这些类将最先实现初始化。 在类的层次结构中,应⽤程序类CWinApp是⼀个基于MFC应⽤程序的最外层对象容器,它不仅拥有诸如实例句柄等需要被传送到WinMain()函数中去的参数,还包含了应⽤程序的主框架窗⼝,当主框架窗⼝被关闭时,应⽤程序也就跟着结束了。因此,开发⼈员必须为程序创建⼀个全局的应⽤程序对象。
2)说说CView类的⼦类都有什么。
视图类(CView)的三个⼦类
CScrollView类提供视图的滚动显⽰;CEditView类⽀持在视图中的⽂本编辑操作;CHtmlView类⽀持在视图中显⽰和操作html⽂件。
3)DLL的三种调⽤形式。
DLL的概念
可以向程序提供⼀些函数、变量或类。
静态链接库与动态链接库的区别:
(1)静态链接库与动态链接库都是共享代码的⽅式。静态链接库把最后的指令都包含在最终⽣成的EXE⽂件中了;动态链接库不必被包含在最终EXE⽂件中,EXE⽂件执⾏时可以“动态”地引⽤和卸载这个与EXE独⽴的DLL⽂件。
(2)静态链接库中不能再包含其他的动态链接库或者静态库,⽽在动态链接库中还可以再包含其他的动态或静态链接库。
DLL分类:
1。Non-MFC DLL(⾮MFC动态库):不采⽤MFC类库结构,其导出函数为标准的C接⼝,能被⾮MFC或MFC编写的应⽤程序所调⽤;2。MFC Regular DLL(MFC规则DLL):⾮MFC动态库MFC规则DLL 包含⼀个继承⾃CWinApp的类,但其⽆消息循环;
3。MFC Extension DLL(MFC扩展DLL):采⽤MFC的动态链接版本创建,它只能被⽤MFC类库所编写的应⽤程序所调⽤。
4)说说onpaint()和ondraw()的关系。
问题:我在视图画的图象或者⽂字,当窗⼝改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上⾯的问题,有什么不同?
答:OnDraw()和OnPaint()好象兄弟俩,因为它们的⼯作类似。
⾄于不见了的问题简单,因为当你的窗⼝改变后,会产⽣⽆效区域,这个⽆效的区域需要重画。⼀般Windows会发送两个消息
WM_PAINT(通知客户区 有变化)和WM_NCPAINT(通知⾮客户区有变化)。⾮客户区的重画系统⾃⼰搞定了,⽽客户区的重画需要我们⾃⼰来完成。这就需要OnDraw()或 OnPaint()来重画窗⼝。
OnDraw()和OnPaint()有什么区别呢?⾸先:我们先要明确CView类派⽣⾃CWnd类。⽽OnPaint()是CWnd的类成员,同时负责响应
WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你⽤VC成的程序代码时,在视图类只有OnDraw没有OnPaint的原因。
其次,要想在屏幕上绘图或显⽰图形,⾸先需要建⽴设备环境DC。其实DC是⼀个数据结构,它包含输 出设备(不单指你17⼨的纯屏显⽰器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响 应,⽽CPaintDC⽀持重画。
当视图变得⽆效时(包括⼤⼩的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调⽤视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。
///CView默认的标准的重画函数
void CView::OnPaint()
{
CPaintDC dc(this);
OnPreparDC(&dc);
OnDraw(&dc); //调⽤了OnDraw
}
既然OnPaint最后也要调⽤OnDraw,因此我们⼀般会在OnDraw函数中进⾏绘制。下⾯是⼀个典型的程序
///视图中的绘图代码⾸先检索指向⽂档的指针,然后通过DC进⾏绘图调⽤。
void CMyView::OnDraw( CDC* pDC )
{
CMyDoc* pDoc = GetDocument();
CString s = pDoc->GetData(); // Returns a CString
CRect rect;
GetClientRect( &rect );
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}
最后:现在⼤家明⽩这哥俩之间的关系了吧。因此我们⼀般⽤OnPaint维护窗⼝的客户区(例如我们的窗⼝客户区加⼀个背景图⽚),⽤OnDraw维护视图的客户区(例如我们通过⿏标在视图中画图)。当然你也可以不按照上⾯规律来,只要达到⽬的并且没有问题,怎么⼲都成。
补充:我们还可以利⽤Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗⼝
5)说说CView类与CDocument的关系(重要)。
CView有⼀个成员变量CDocument* m_pDocument,指向相关的Documente.
Document和view交谈过程:
1 使⽤者在Viewl做动作(View扮演使⽤者接⼝的第⼀线)。
2 Viewl调⽤GetDocument,取得Document指针,更改资料内容。
3 Viewl调⽤Document的UpdateAllViews。
4 View2和View3的OnUpdate⼀⼀被调⽤起来,这是更新画⾯的时机。
CView::OnUpdate被调⽤,代表着View被告知:“嘿,Document的内容⼰经改变了,请你准备修改你的显⽰画⾯”。如果你想节省⼒⽓,利⽤Invalidate(TRUE)把窗⼝整个设为重绘区(⽆效区)并产⽣WM_PAINT,再让CView::OnDraw去伤脑筋算了。但是全部重绘的效率低落,程序看起来很笨拙。
6)说SendMessage()与PostMessage()的区别。
PostMessage和SendMessage的区别
1, PostMessage只把消息放⼊队列,不管其他程序是否处理都返回,然后继续执⾏,这是个异步消息投放函数。⽽SendMessage必须等待其他程序处理消息完了之后才返回,继续执⾏,这是个同步消息投放函数。⽽且,PostMessage的返回值表⽰PostMessage函数执⾏是否正确;⽽SendMessage的返回值表⽰其他程序处理消息后的返回值。这点⼤家应该都明⽩。
2, 如果在同⼀个线程内,PostMessage发送消息时,消息要先放⼊线程的消息队列,然后通过消息循环Dispatch到⽬标窗⼝。
SendMessage发送消息时,系统直接调⽤⽬标窗⼝的消息处理程序,并将结果返回。SendMessage在同⼀线程中发送消息并不⼊线程消息队列。 如果在不同线程内。最好⽤PostThreadMessage代替PostMessage,他⼯作的很好。SendMessage发送消息到⽬标窗⼝所属的线程的消息队列,然后发送消息的线程等待(事实上,他应该还在做⼀些监测⼯作,⽐如监视QS_SENDMESSAGE标志),直到⽬标窗⼝处理完并且结果返回,发送消息的线程才继续运⾏。这是SendMessage的⼀般情况,事实上,处理过程要复杂的多。⽐如,当发送消息的线程监测到有别的窗⼝SendMessage⼀个消息到来时,他直接调⽤窗⼝处理过程(重⼊),并将处理结果返回(这个过程不需要消息循环中GetMessage等的⽀持)。
3, msdn: If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters can not include pointers. Otherwise, the operation will fail. 如果发送的消息码在WM_USER之下(⾮⾃定义消息)且消息参数中带有指针,那么
PostMessage,SendNotifyMessage,SendMessageCallback这些异步消息发送函数将会调⽤失败。 最好不要⽤PostMessage发送带有指针参数的消息。
7)简述COM技术。
COM(Component Object Model,),是由微软推出的⼀规范,通过设定不同组件之间需要遵守的标准与协议,主要⽤来跨语⾔、跨进程之间的模块通信。所谓COM(Component Object Model,)是⼀种说明如何建⽴可动态互变组件的规范,此规范提供了为保证能够,客户和组件应遵循的⼀些和。通过这种标准将可以在任意两个组件之间进⾏通信⽽不⽤考虑其所处的操作环境是否相同、使⽤的开发语⾔是否⼀致以及是否运⾏于同⼀台计算机。
8)说说读写⼀个⽂件怎么来完成,分别⽤c,c++,MFC三种库函数来编写代码。
对⽂件读写的三种⽅法
1.C中
FILE *pFile=fopen("1.txt","w");
fwrite("");
//fseek(pFile,0,SEEK_SET);
//fwrite("ftp:",1,strlen("ftp:"),pFile);
//fwrite("");
fclose(pFile);*/
//fflush(pFile);
表头⽂件 #include<stdio.h>
FILE * fopen(const char * path,const char * mode);
  函数说明 参数path字符串包含欲打开的⽂件路径及⽂件名,参数mode字符串则代表着流形态。
  mode有下列⼏种形态字符串:
int fseek( FILE *stream, long offset, int origin );
  第⼀个参数stream为⽂件指针
  第⼆个参数offset为偏移量,整数表⽰正向偏移,负数表⽰负向偏移
  第三个参数origin设定从⽂件的哪⾥开始偏移,可能取值为:SEEK_CUR、 SEEK_END 或 SEEK_SET
  SEEK_CUR: 当前位置
  SEEK_END: ⽂件结尾
  SEEK_SET: ⽂件开头
  其中SEEK_CUR,SEEK_END和SEEK_SET依次为1,2和0
:fwrite(buffer,size,count,fp);
  (1)buffer:是⼀个指针,对fwrite来说,是要输出数据的地址。
  (2)size:要写⼊的字节数;
  (3)count:要进⾏写⼊size字节的数据项的个数;
  (4)fp:⽬标⽂件指针。
int fread(void *ptr, int size, int nitems, FILE *stream);
  参 数:⽤于接收数据的地址(指针)(ptr)
  单个元素的⼤⼩(size)
  元素个数(nitems)
  提供数据的⽂件指针(stream)
:int fflush(FILE *stream)
功 能: 清除⽂件缓冲区,⽂件以写⽅式打开时将缓冲区内容写⼊⽂件
2.C++中
/* ofstream ofs("4.txt");
ofs.write(""));
ofs.close();*/
要包括头⽂件 "fstream.h"
3.MFC中 ⽤CFile类,哈哈!简单好⽤
CFileDialog fileDlg(FALSE);
postthreadmessage
fileDlg.m_ofn.lpstrTitle="我的⽂件保存对话框";
fileDlg.m_ofn.lpstrFilter="Text Files(*.txt)\0*.txt\0All Files(*.*)\0*.*\0\0";
fileDlg.m_ofn.lpstrDefExt="txt";
if(IDOK==fileDlg.DoModal())
{
CFile file(fileDlg.GetFileName(),CFile::modeCreate | CFile::modeWrite);
file.Write(""));
file.Close();
}
9)说说⼆进制⽂件和⽂本⽂件之间区别,举例⼦,会吗?
作者:中正
链接:www.zhihu/question/19971994/answer/36121103
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
⼴义上的⼆进制⽂件包括⽂本⽂件,这⾥讨论的是狭义上的⼆进制⽂件与⽂本⽂件的⽐较:
1. 能存储的数据类型不同
⽂本⽂件只能存储char型字符变量。
⼆进制⽂件可以存储char/int/short/long/float/……各种变量值。
2. 每条数据的长度
⽂本⽂件每条数据通常是固定长度的。以ASCII为例,每条数据(每个字符)都是1个字节。
⼆进制⽂件每条数据不固定。如short占两个字节,int占四个字节,float占8个字节……
3. 读取的软件不同
⽂本⽂件编辑器就可以读写。⽐如记事本、NotePad++、Vim等。
⼆进制⽂件需要特别的解码器。⽐如bmp⽂件需要图像查看器,rmvb需要播放器……
4. 操作系统对换⾏符('\n')的处理不同 (不重要)
⽂本⽂件,操作系统会对'\n'进⾏⼀些隐式变换,因此⽂本⽂件直接跨平台使⽤会出问题。
在Windows下,写⼊'\n'时,操作系统会隐式的将'\n'转换为"\r\n",再写⼊到⽂件中;读的时候,会把“\r\n”隐式转化为'\n',再读到变量中。
在Linux下,写⼊'\n'时,操作系统不做隐式变换。
⼆进制⽂件,操作系统不会对'\n'进⾏隐式变换,很多⼆进制⽂件(如电影、图⽚等)可以跨平台使⽤。
10)的技术优点是何?
⼀:什么是.NET?它包括什么?
.Net是为简化在第三代因特⽹的⾼分布式环境下的应⽤程序开发,基于开放互联⽹标准和协议之上,
实现异质语⾔和平台⾼度交互性,⽽构建的新⼀代计算和通信平台。
.Net主要包括公共语⾔运⾏时(CommonLanguage Runtime)和.Net构架类库。
⼆: .NET的主要优点有哪些?
.Net的主要优点有跨语⾔,跨平台,安全,以及对开放互联⽹标准和协议的⽀持.
<a>.Net⽀持多种语⾔的互操作,即在⼀种语⾔下开发的组件,可在另⼀组件下通过⾯向对象的继承⽽得
以重⽤,⽬前.Net⽀持的语⾔达⼆⼗多种。
<b>.Net通过将各语⾔先编译成中间语⾔(IL),然后再执⾏时⽤即时编译器(Just In Time)将之编译成本
地平台代码来实现异构平台下对象的互操作,⽬前.Net⽀持的平台有Windows,Linux和Unix的⽀持正
在开发中。
<c>.Net通过公共语⾔运⾏时(Common LanguageRuntime)来实现资源对象,类型的安全.
<d>.Net通过对HTTP,XML,SOAP,WSDL等Internet标准的强劲⽀持提供在异构⽹络环境下获取远程服务,
连接远程设备,交互远程应⽤的编程界⾯.
11).关于MFC的消息机制。
MFC使⽤⼀种消息映射机制来处理消息,在应⽤程序框架中的表现就是⼀个消息与消息处理函数⼀⼀对应的消息映射表,以及消息处理函数的声明和实现等代码。当窗⼝接收到消息时,会到消息映射表中查该消息对应的消息处理函数,然后由消息处理函数进⾏相应的处理。SDK编程时需要在窗⼝过程中⼀⼀判断消息值进⾏相应的处理,相⽐之下MFC的消息映射机制要⽅便好⽤的多。
12).进程/线程间的通信
线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是⼀个线程的数据可以直接提供给其他线程使⽤,⽽不必通过操作系统(也就是内核的调度)。
进程间的通信则不同,它的数据空间的独⽴性决定了它的通信相对⽐较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了⽹络通信。
进程的通信机制主要有:管道、有名管道、消息队列、信号量、共享空间、信号、套接字。
管道:它传递数据是单向性的,只能从⼀⽅流向另⼀⽅,也就是⼀种半双⼯的通信⽅式;只⽤于有亲缘关系的进程间的通信,亲缘关系也就是⽗⼦进程或兄弟进程;没有名字并且⼤⼩受限,传输的是⽆格式的流,所以两进程通信时必须约定好数据通信的格式。管道它就像⼀个特殊的⽂件,但这个⽂件之存在于内存中,在创建管道时,系统为管道分配了⼀个页⾯作为数据缓冲区,进程对这个数据缓冲区进⾏读写,以此来完成通信。其中⼀个进程只能读⼀个只能写,所以叫半双⼯通信,为什么⼀个只能读⼀个只能写呢?因为写进程是在缓冲区的末尾写⼊,读进程是在缓冲区的头部读取,他们各⾃的不同,所以功能不同。
有名管道:看见这个名字就能知道个⼤概了,它于管道的不同的是它有名字了。这就不同与管道只能在具有亲缘关系的进程间通信了。它提供了⼀个路径名与之关联,有了⾃⼰的传输格式。有名管道和管道的不同之处还有⼀点是,有名管道是个设备⽂件,存储在⽂件系统中,没有亲缘关系的进程也可以访问,但是它要按照先进先出的原则读取数据。同样也是单双⼯的。
消息队列:是存放在内核中的消息链表,每个消息队列由消息队列标识符标识,于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除⼀个消息队列,内核重启也就是系统重启,同样消息队列的⼤⼩也是受限制的。
信号量:也可以说是⼀个计数器,常⽤来处理进程或线程同步的问题,特别是对临界资源的访问同步问题。临界资源:为某⼀时刻只能由⼀个进程或线程操作的资源,当信号量的值⼤于或等于0时,表⽰可以供并发进程访问的临界资源数,当⼩于0时,表⽰正在等待使⽤临界资源的进程数。更重要的是,信号量的值仅能由PV操作来改变。
共享内存:就是分配⼀块能被其他进程访问的内存。共享内存可以说是最有⽤的进程间通信⽅式,也是最快的IPC形式。⾸先说下在使⽤共享内存区前,必须通过系统函数将其附加到进程的地址空间或说为映射到进程空间。两个不同进程A、B共享内存的意思是,同⼀块物理内存被映射到进程A、B各⾃的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同⼀块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。采⽤共享内存通信的⼀个显⽽易见的好处是效率⾼,因为进程可以直接读写内存,⽽不需要任何数据的拷贝。对于像管道和消息队列等通信⽅式,则需要在内核和⽤户空间进⾏四次的数据拷贝,⽽共享内存则只拷贝两次数据[1]:⼀次从输⼊⽂件到共享内存区,另⼀次从共享内存区到输出⽂件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建⽴共享内存区域。⽽是保持共享区域,直到通信完毕为⽌,这样,数据内容⼀直保存在共享内存中,并没有写回⽂件。共享内存中的内容往往是在解除映射时才写回⽂件的。因此,采⽤共享内存的通信⽅式效率是⾮常⾼的。
信号:信号是在软件层次上对中断机制的⼀种模拟,在原理上,⼀个进程收到⼀个信号与处理器收到
⼀个中断请求可以说是⼀样的。信号是异步的,⼀个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。信号是进程间通信机制中唯⼀的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发⽣了。信号机制经过POSIX实时扩展后,功能更加强⼤,除了基本通知功能外,还可以传递附加信息。信号事件的发⽣有两个来源:硬件来源(⽐如我们按下了键盘或者其它硬件故障);软件来源。信号分为可靠信号和不可靠信号,实时信号和⾮实时信号。进程有三种⽅式响应信号1.忽略信号2.捕捉信号3.执⾏缺省操作。
套接字:套接字是通信端点的抽象,就是这个通信端点的逻辑代表。
13.)线程同步与互斥

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。