友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
C语言实例教程(PDF格式)-第38部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
出一个字体对话框让用户为该字符串选定字体。方法是使用下面的代
…………………………………………………………Page 433……………………………………………………………
码替换OnNewDocument的实现代码中的// TODO注释:
m_str=〃您好; 欢迎使用本程序!〃;
CFontDialog dlg;
dlg。GetCurrentFont(&m_lf);
// 将用户选定的字体信息填充到LOGFONT类型的结构m_lf中,以供视类使用
if(dlg。DoModal()==IDOK)
dlg。GetCurrentFont(&m_lf);
4。 再重复一下,在MFC应用程序中,文档类是和视类一起协作以完成
应用程序功能的。下面我们将为Example程序的视类CExampleView类
的OnDraw成员函数添加一些代码,以将文档类中的m_str成员变量的
内容显示到视的框架窗口中。关于视类的内容是在本章的 “8。4 生
成视” 一节中讲述的。在本节,为了使应用程序完整并且能够运
行,以反映我们对文档类所进行的一些操作,书中给出一些用于视类
的代码,并且,为了使章节的行文连贯和有重点,我们并不详细的讲
解这些代码。如果您还不是很了解视类的话,大可不必去在意这些代
码究竟都是怎样工作的,以及为什么要这样书写这些代码,把本书继
续看下去,这些代码都不会成其为问题。但若您现在很想了解这些内
容,那也不妨跳过去浏览一下 “8。4 生成视” 以及 “图形设备接
口”一章。
这里我们用下面的代码来替换类CExampleView的OnDraw成员函数。
// 获取当前客户区的大小
CRect rectClient;
GetClientRect(rectClient);
CSize sizeClient=rectClient。Size();
// 从文件中读取数据
CString str=pDoc…》m_str;
LOGFONT lf=pDoc…》m_lf;
// 使字体充满整个客户区
lf。lfHeight=sizeClient。cy;
lf。lfWidth=long(sizeClient。cx/str。GetLength());
…………………………………………………………Page 434……………………………………………………………
// 用当前字体信息生成CFont对象
CFont *pFont=new CFont;
pFont…》CreateFontIndirect(&lf);
// 改变当前所用字体,并保存旧字体
CFont *pOldFont=pDC…》SelectObject(pFont);
// 用新选定的字体绘制字符串 〃您好; 欢迎使用本程序!〃
CSize sizeTextExtent=pDC…》GetTextExtent(str);
pDC…》TextOut((sizeClient。cx…sizeTextExtent。cx)/2;
(sizeClient。cy…sizeTextExtent。cy)/2;
str);
// 恢复系统默认字体
pDC…》SelectObject(pOldFont);
在上面的示例程序中,我们在文档类中定义了两个公有的成员变量
m_str和m_lf,然后在视类的OnDraw成员函数中访问了这两个成员变
量,通过这些变量从文档中获取所要显示的字符串和所使用的字体。
很多时候我们常使用的是另外一种方法,即把成员变量定义为私有或
保护成员,然后添加存取该成员变量的函数。如下面的代码所示:
protected:
CString m_str;
public:
CString GetStr()
{
CString *pStr=new CString;
*pStr=m_str;
return *pStr;
}
这样的好处是可以防止数据成员被从类外部修改,从而维护了类中数
…………………………………………………………Page 435……………………………………………………………
据的安全。
l 注意:
l 不象很多资料上所说的那样,在GetStr函数中使用下面的代码,
并不能保证类中的保护成员绝对不会被从外部修改:
l CString GetStr()
l {
l return m_str;
l }
这时,如果类的使用者在外部使用了如下面的语句所示的强
制类型转换,
l CString& str=(CString&)pDoc…》GetStr()
l str=〃字符串将被修改 !〃
则可以通过引用str来修改类中的保护性成员m_str的值,读
者可以编写程序来 自行验证这一点。
但如果不使用强制类型转换将pDoc…》GetStr转换为CString&
并把str定义为CString (而不是CString&)的话,修改str并
不会改变类中的保护成员m_str的值。
l 使用以const关键字修饰的指针来返回指向私有或保护性数据成 员
的指针也并不总是安全的。例如,若GetStr函数的定义如下:
l const CString* GetStr()
l {
l return (const CString*)&m_str;
l }
那么,在类的外部,使用者同样可以使用强制类型转换被声
明为const的指针,从而修改私有成员m_str,如下面的代码
所示:
…………………………………………………………Page 436……………………………………………………………
l CString *pStr=(CString *)pDoc…》GetStr();
l *pStr=〃字符串将被修改 !〃;
l 虽然我们不应该过多地使用这种强制类型转换,但是,在编写类
的时候,还是要尽可能的避免可能出现这些不希望发生的事情,
以免用户对类的不正当的使用导致某些意外的问题,如使类中的
数据不再可用等。如果调用者对 自己的所做不是很清楚的话,这
很可能导致程序出错,并且难以被检查出来,因为很多的编程者
(尤其是初学者) 一般不容易想到问题的根源出在类的内部,尽管
这种问题是由于错误的使用类造成的。
与添加读取文档数据的公有函数相似,我们还可以添加设置文档数据
的公有成员函数,如下面的代码所示:
public:
int SetStr(const CString& NewStr)
{
m_str=NewStr;
}
使用公有成员函数来存取类中的数据的一个最大的好处在于可以验证
用户所传递的数据的有效性。从而避免用户把一个非法的数据赋给类
的成员变量,这有可能在后面的使用中导致意外的问题。
8。3。3 串行化数据
在Visual C++术语中,我们把对象的保存到永久介质中或从永久介质
中读取对象称作串行化。串行化的基本观点是每一个对象都应该能够
将 自身的当前数据保存到永久介质中,这些数据一般由其成员变量所
提供;在需要的时候,对象还应该能够从永久介质中读出所保存的数
据,并用这些数据来重建该对象。在本节中,我们只讨论最基本串行
化操作,在 “8。3。5 串行化对象” 一节中描述了串行化对象和生成
可串行化对象所需要的附加信息。
…………………………………………………………Page 437……………………………………………………………
图8。7 保存文件时的串行化过程
在文档/视结构实现中,串行化一般是重载文档对象的Serialize成员
函数。在AppWizard创建应用程序框架的时候,生成了一个Serialize
重载函数的框架,如下面的代码所示:
void CExampleDoc::Serialize(CArchive& ar)
{
if (ar。IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
图8。7描述了保存文档时的串行化过程。
…………………………………………………………Page 438……………………………………………………………
图8。8 打开文档时的串行化过程
图8。8描述了打开文档时的串行化过程。
由图8。7和图8。8可以看出,无论是保存文档或是打开文档,应用程序
都是通过调用文档类的Serialize成员函数来完成串行化操作的。因
此,在大多数情况下,我们都通过重载Serialize成员函数来实现文
档的串行化。Serialize成员函数带有一个CArchive类型的参数,这
是一个与所打开的文件相关联的对象。一般情况下,我们总是使用
CArchive对象来保存和打开文档。
一个CArchive对象和一个标准的C++输入/输出流相类似,可以使用
C++析取运算符》》和插入运算符var和ar
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!