}
};
intmain()
{
Base*p=newchild_1;//父类指针指向子类对象
p->Print();
deletep;//记住释放,否则内存泄露
p=newchild_2;
p->Print();
deletep;
p=NULL;
return0;
}
三.详细描述你所理解的MFC的文档视图架构。
MFC文档/视图结构结构被认为是一种架构,
应用程序的大部分代码都会被添加在文档和视图中。
文档和视图紧密相连,是用户与文档之间的交互窗口;用户通过文档视图结构可实现数据的传输,编辑读取和保存等。
但文档,视图,以及应用程序框架的相关部分之间还包括了一系列非常复杂的相互作用。
切分窗口和一档多视是文档和视图相互作用的典型实例。
文档用于管理应用程序的数据,而视图用于显示文档并管理与用户的交互编写应用程序时,大部分工作都集中在文档类和视图类中。
在创建应用程序的框架时,MFcAppWizard创建的文档类从CDocument类派生而来,视图类从CView类为应用程序定义的视图类提供了一些基本功能。
视图与文档链接在一起,它在文档与用户之间起中介作用。
视图在屏幕上显示文档数据并把用户输入转换成对文档的操作。
类库中文档与视图的这种实现方法把数据与数据的所有更改都通过文档类管理,而视图则调用这个接口来访问和更新数据。
文档及相关的视图和边框窗口由文档模板创建的,文档模板负责创建并管理某种类型的所有文档。
一文档与视图的相互作用
正常情况下,MFC应用程序用一种编程模式使程序中的数据与它的显示型式和用户交互分离开来,这种模式就是“文档视图结构”也就是文档视图架构,文档视图结构可以方便地实现文档和视图的相互作用。
如果在用MFCAppWizard创建文档应用程序的第一步选中“文档视图结构支持”复选框,就可使用下列五个文档和视图相互作用的重要成员函数。
1.CView:
:
GetDocument函数
视图对象只有一个与之相联系的文档对象,它所包含的GetDocument函数允许应用程序由视图得到与之相关的文档。
2.CDocument:
:
UpdateAllview函数
如果文档的数据发生了改变,那么所有的视图都必须被通知到,以便它们能够对所显示的数据进行相应的更新。
CDocument:
:
UpdateAllview函数就起到这样的作用。
1.CView:
:
OnUpdate函数
这是一个虚函数。
当应用程序调用了CDocument:
:
UPdateAll
3.CView:
:
OnInitialUpdate函数
当应用程序被启动时,或当用户从“文件”菜单中选择了“新建”或打开时,该View虚函数都会被自动调用。
该函数除了调用无提示参数(lHint=0,pHint=NULL)的OnUpdate函数之外没有其他任何操作
4.CDocument:
:
OnNewDocument函数
在文档应用程序中,当用户从文件菜单中选择新建命令时,框架将首先构造一个文档对象,然后调用该函数。
在MFC中,文档视图机制使框架窗口,文档,视图和应用程序对象之间具有一定的联系,通过相应的函数可实现各对象指针的相互调用。
1.从文档类中获取视图对象指针
在文档类中有一个与其关联的各视图对象的列表,并可通过CDocument类的成员函数GetFirstViewPosition和GetNexView来定位相应的视图对象
2.从视图类中获取文档对象和住框架对象指针
在视图类中获取文档对象指针是很容易的,只需调用视图类中的成员函数GetDocument即可。
3.在主框架类中获取视图对象指针
对于单文档应用程序来说,只需调用CFramWnd类的GetActiveView成员函数即可。
文档/视图结构特点主要有:
1.将对数据的操作与数据显示界面分离,放在不同类的对象中处理。
这种思想使得程序模块的划分更加合理。
文档对象只负责数据的管理,不涉及用户界面;视图对象只负责数据输出和与用户的交互,可以不考虑数据的具体组织结构的细节。
2.MFC在文档/视图结构中提供了许多标准的操作界面,包括新建文件、打开文件、保存文件、文档打印等,大大减轻了程序员的工作量。
程序员不必再书写这些标准处理的代码,从而可以把更多的精力放到完成应用程序特定功能的代码上。
3.支持打印、打印预览和电子邮件发送功能。
程序员只需要编写很少的代码甚至根本无需编写代码,就可以为应用程序提供“所见即所得”式的打印和打印预览这类功能。
4.使用DeveloperStudio的AppWizard可生成基于文档/视结构的SDI或MDI框架程序,程序员只需在其中添加与特定应用有关的部分代码,就可完成应用程序的开发工作。
然而,文档/视图结构也不是万能的。
有些不宜采用文档/视图结构:
四选修题
面向对象的3大基本特征有封装性、继承性和多态性:
完成一个简单的基于MFC对话框的个人通信录系统(界面布局和系统需求自己确定),详细描述你的分析以及实现过程,通讯录的数据以串行化的方法写入文件。
(60分)
1.分析过程
完成一个简单的基于MFC对话框的个人通讯录系统。
它以对话框的方式弹出界面,记录包括姓名,学号,地址,电话和QQ这些信息,用类CBook1来描述,并使其可序列化。
然后将记录保存到一个对象数组集合类对象中,最后通过文档序列化将记录保存到一个文件中。
当添加记录或打开文件时,还会将数据显示在文档窗口中(即视图)
图1Ex_Book1运行结果
2.基于MFC对话框的个人通讯录系统的实现过程。
1.添加用于学生记录输入的对话框
(1)用MFCAppWizard(exe)创建一个默认的单文档应用程序Ex_Book1.
(2)像应用程序中添加一个对话框资源,打开属性对话框,将其字体设置为“宋体,9号”,标题改为“添加学生记录”,取默认的ID(IDD_DIALOG1),将“OK”和“Cancel”按钮的标题分别改为“确定”和“取消”。
(3)参看图1的控件布局,用编辑器为对话框架添加如图表2所示的一些空件。
表2添加的控件
控件
ID
标题
属性
静态文本
默认
姓名
默认
静态文本
默认
学号
默认
静态文本
默认
地址
默认
静态文本
默认
电话
默认
静态文本
默认
QQ
默认
编辑框
IDC_EDIT1
默认
编辑框
IDC_EDIT2
默认
编辑框
IDC_EDIT3
默认
编辑框
IDC_EDIT4
默认
编辑框
IDC_EDIT5
默认
(1)双击对话框模板或按【Ctrl+W】快捷键,为对话框资源IDD_DIALOG1创建一个对话框类CInputDlg.
(2)打开ClassWizard的MemberVariables标签,在Classname中选择CInputDlg,选中所需的控件ID标识符,双击鼠标或单击AddVariables按钮,依次为表3所示的控件增加成员变量。
表3控件变量
控件ID
变量类型
变量名
范围和大小
IDC_EDIT1
CString
m_strName
20
IDC_EDIT2
CString
m_strID
20
IDC_EDIT3
CString
m_strAdr
20
IDC_EDIT4
CString
m_strPhone
20
IDC_EDIT5
CString
m_strQQ
20
图4控件变量
1.添加一个CBook1类并使该类可序列话
一个可序列列化的类要是CObject的一个派生类,且在类声明中,需要包含DECLARE_SERIAL宏调用,而在类的实现文件中包含IMPLEMENT_SERIAL宏调用,这个宏有3个参数:
前两个参数分别表示类名和基类名,第三个参数表示应用程序的版本号。
最后还要重载Serialize函数,使该类的数据成员进行相关序列化操作。
由于使用ClassWizard无法添加一个CObject派生类,因此必须手动进行,为了简化类文件的复杂性,这里创建的这个CBook1类的声明和实现代码是直接添加在Ex_Book1Doc.h和Ex_Book1Doc.cpp文件中的,具体代码如下
classCBook1:
publicCObject
{
CStringstrName;//姓名
CStringstrID;//学号
CStringstrAdr;//地址
CStringstrPhone;//电话
CStringstrQQ;//QQ
DECLARE_SERIAL(CBook1)
public:
CBook1(){};
CBook1(CStringname,CStringid,CStringadr,CStringphone,CStringqq);//
voidSerialize(CArchive&ar);
voidDisplay(inty,CDC*pDC);//在坐标为(0,Y)处显示数据
};
CBook1:
:
CBook1(CStringname,CStringid,CStringadr,CStringphone,CStringqq)
{
strName=name;
strID=id;
strAdr=adr;
strPhone=phone;
strQQ=qq;
}
voidCBook1:
:
Display(inty,CDC*pDC)
{
CStringstr;
str.Format("%s%s%s%s%s",strName,strID,strAdr,strPhone,strQQ);
pDC->TextOut(0,y,str);
}
IMPLEMENT_SERIAL(CBook1,CObject,1)
voidCBook1:
:
Serialize(CArchive&ar)
{
if(ar.IsStoring())
ar<else
ar>>strName>>strID>>strAdr>>strPhone>>strQQ;
}
3.添加并处理菜单项
(1)在菜单资源的主菜单中增加顶层菜单项“学生记录(&S)”,在该顶层菜单项中增加子菜单“添加(&A)”(ID_BOOK1_ADD)
(2)用ClassWizard为CEx_Book1Doc类添加ID_BOOK1_ADD的COMMAND消息映射,并在映射函数添加代码;
(3)在Ex_Book1Doc.cpp.h文件的开始处,增加包含CAddDlg的头文件。
2.完善代码
(1)在Ex_Book1Doc.h文件中,为CEx_Book1Doc类添加下列成员变量和函数;
public:
CObArraym_booObArray;
intGetAllRecNum();
CBook1*GetBookAt(intnIndex);
(2)在Ex_Book1Doc.cpp文件中,添加函数的实现代码:
CBook1*CEx_Book1Doc:
:
GetBookAt(intnIndex)
{
if((nIndex<0)||nIndex>m_booObArray.GetUpperBound())
return0;//超界处理
return(CBook1*)m_booObArray.GetAt(nIndex);
}
intCEx_Book1Doc:
:
GetAllRecNum()
{
returnm_booObArray.GetSize();
}
(3)在CEx_Book1Doc析构函数中添加下列代码:
CEx_Book1Doc:
:
~CEx_Book1Doc()
{
intnIndex=GetAllRecNum();
while(nIndex--)
deletem_booObArray.GetAt(nIndex);
m_booObArray.RemoveAll();
}
(4)在Serialize函数中添加下列代码:
voidCEx_Book1Doc:
:
Serialize(CArchive&ar)
{
if(ar.IsStoring())
{
m_booObArray.Serialize(ar);
}
else
{
m_booObArray.Serialize(ar);
}
}
还有要说的是,m_booObArray是一个对象数组集合类CObArray的对象,当读取数据过程中调用Serialize成员函数时,它实际上是调用集合类对象中元素的Serialize成员函数,并将对象添加到m_booObArray中。
当通讯录信息记录后,一旦保存到文件中,就会将CBook1类名同时存到文件中,当读取时,就会自动使用CBook1类这是CObArray序列化的一个内部机制。
(5)在CEx_Book1View:
:
OnDraw函数中添加下列代码:
voidCEx_Book1View:
:
OnDraw(CDC*pDC)
{
CEx_Book1Doc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
inty=0;
for(intnIndex=0;nIndexGetAllRecNum();nIndex++)
{
pDoc->GetBookAt(nIndex)->Display(y,pDC);
y+=16;
}
(6)打开文档的字串资源IDR_MAINFRAME,将其内容修改为;
Ex_Book1Rec\nEx_Boo\n记录文件(*.rec)\nExBook1.Document\nEx_BooDocument
(7)编译运行并测试,结果如图1所示。
二.通讯录系统演示如下
1.程序主界面如下
图5主界面
2.资源框界面如下
图5资源框界面
3.通讯录信息如下
图6通讯录信息
4.保存功能如下
图7保存功能
5.打开功能如下
图8打开功能