📄 chapter2.txt
字号:
*消除函数和变量名的冲突
*类是语言的自然扩展
*通常,精心设计的库减少了代码量
利用基础类库,创建一个窗口所需的代码大约只占传统应用程序的三分之一。这就可以使程序员只用花很少的时间与Windows打交道,把更多的精力集中在开发自己的程序代码上。
22.2 MFC的设计考虑
基础类库设计小组定义了严格的设计规则,在设计MFC库时必须遵循这些规则。这些规则和方针如下:
*利用C++的威力,但不能把程序员吓倒
*使从标准API调用到类库的转换尽可能简单
*允许混合使用传统的函数调用和新的类库
*在设计类库的时候综合考虑功能和效率
*建成的类库必须能够方便地在不同平台间移植,如Windows 95和Windows NT
设计小组感到要开发高质量的代码必须从MFC库本身开始。C++基础类库必须又小又快。它的简单性使它易于使用,而执行速度与庞大的C函数库接近。
这些类的设计方式应该让熟练的Windows程序员不必重新学习各种函数的名字。通过仔细的命名和设计可以实现这一点。Microsoft认为这一点是MFC区别于其它类库的一个特征。
MFC小组还把基础类库设计为是允许以混合方式编程的。这就是说,在同一个源文件里,既可以使用类也可以使用传统的函数调用。即使是在使用MFC时,类似SetCursor()和GetSystemMetrics()这样的函数还是需要直接调用。
Microsoft也知道类库必须方便使用。其它厂商提供的一些类库设计得太抽象。按Microsoft的说法,这些笨重的类企图生成又大又慢的应用程序。MFC库提供了合理的抽象,保证代码很小。
开发小组将原始的MFC库设计为动态的而不是静态的。动态的结构是这些类可以适应我们现在使用的Windows 95和Windows NT环境。
22.3 MFC库的关键特性
从其它编译器厂商那儿也可以获得Windows类库,但Microsoft宣称他们的MFC类库具有许多真正的优点:
*全面支持所有的Windows函数、控件、消息、GDI(图形设备接口)绘图原语、菜单以及对话框。
*使用与Windows API相同的命名约定。因此,从名字上就可以直接知道类的功能。
*消除了一个错误源,即大量的switch/case语句。所有的消息都被映射到类的成员函数。这种消息-方法的映射方法应用于所有的消息。
*能够把对象的信息输出到文件,这提供了更好的诊断支持。同时还提供了验证成员变量的能力。
*增强的例外处理设计,使得程序代码失败的可能性更小。能够解决“内存不足”以及其它一些问题。
*可以在运行时决定数据对象的类型。这允许对类的域进行动态操纵。
*小而快速的代码。前面已经提到,MFC库只添加了很少一些代码,执行起来几乎与传统的C语言Windows应用程序一样快。
*对组件对象模型(COM)的支持。
有经验的Windows程序员会立刻喜欢上其中的两个特性:熟悉的命名约定和消息-方法映射机制。如果你重新检查一下在第二十一章中开发的应用程序的源代码,你会看到大量用于处理错误的switch/case语句。还应该注意这些应用程序调用了大量的API函数。当你使用MFC库的时候,这两种现象都消失或减少了。
专业程序员肯定会欣赏在MFC库中实现的更好的诊断和很小的代码。现在程序员就可以利用MFC库的好处而不必担心他们的应用程序的代码大小了。
最后,MFC是唯一真正有用的类库。
22.4 一切从CObject类开始
类似MFC这样的类库通常都来自很少的几个基类。然后,另外的类就可以从这些基类中继承而来。CObject是在开发Windows应用程序时大量使用的一个基类。在MFC/INCLUDE子目录下提供的MFC库头文件包括了许多类定义信息。
我们来简单地看一下,CObject,它在头文件AFX。H中有定义:
///////////////
//class CObject is the root of all compliant objects
class CObject
public:
//Object model(types,destruction,allocation)
virtual CRuntimeClass*GetRuntimeClass () const;
virtual~CObject();//virtual destructors are necessary
//Diagnostic allocations
void*PASCAL operator new(size-t nSize);
void*pascal operator new(size-t,void*p);
void PASCAL operator delete(void*p);
#if defined(-DEBUG)&&!defined(-AFX-NO-DEBUG-CRT)
//for file name/line number tracking using DEBUG-NEW
void* PASCAL operator new(size-t nSize,
LPCSTR 1pszFileName,
int nLine);
//Disable the copy constructor and assignment by default
//so you will get compiler errors instead of unexpected
//behavior if you pass objects by value or assign objects.
protected:
CObject();
private:
CObject(const CObject& objectSrc);//no implementation
void operator=(const CObject& objectSrc);
//Attributes
public:
BOOL IsSerializable()const;
BOOL IsKindOf(const CRuntimeClass*pClass)const;
//Overridables
virtual void Serialize (CArchive& ar);
//Diagnostic Support
virtual void AssertValid()const;
virtual void Dump(CDumpContext& dc)const;
//Implementation
public:
static const AFX-DATA CRuntimeClass classCObject;
#ifdef-AFXDLL
static CRuntimeClass*PASCAL-GetBaseClass();
#endif
;
为了清楚起见,对这段代码作了一些细微的改动。但和你在头文件AFX.H可以找到的代码基本一样。
检查CObject的代码,注意构成这个类定义的成分。首先,CObject被分为公有、保护和私有三个部分。CObject还提供了一般的和动态的类型检查以及串行化的功能。回忆一下,动态类型检查使你可以在运行时确定对象的类型。借助于永久性的概念,对象的状态可以被保存到存储介质中,比如磁盘。对象的永久性使对象成员函数也可以是永久的,允许对象数据的恢复。
子类从基类继承而来。例如,CGdiObject是一个从CObject类继承来的类。这儿是AFXWIN。H中找到的CGdiObject类定义。同样,为了清楚起见,对其作了一些改动。
//////////////////////
//CGdiObjet abstract class for CDC SelectObject
class CGdiObject:public CObject
DECLARE-DYNCREATE(CGdiObject)
public:
//Attributes
HGDIOBJ m-hObject;//must be first data member
operator HGDIOBJ()const;
static CGdiObject*PASCAL FromHandle(HGDIOBJ hObject);
static void PASCAL Delete TempMap();
BOOL Attach (HGDIOBJ hObject);
HGDIOBJ Detach();
//Constructors
CGdiobject();//must create a derived class object
BOOL DeleteObject();
//Operations
int GetObject (int nCount,LPVOID 1pObject)const;
UINT GetObjectType()const;
BOOL CreateStockObject(int nIndex);
BOOL UnrealizeObject();
BOOL operator==(const CGdiObject& obj)const;
BOOL operator!=(const CGdiObject& obj)const;
//Implementation
public:
virtual~CGdiObject();
#ifdef-DEBUG
virtual void Dump(CDumpContext& dc)const;
virtual void AssertValid()const;
#endif
;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -