📄 第01章 程序漫谈.htm
字号:
<P>
<P>关于封装,初学阶段最直观的比喻就是抽屉。抽屉将各种<B>对象</B>分门别类地进行存储。譬如中药房,上千种的中药被上千个贴有标签的抽屉“封装”起来,这一充满艺术性的“封装”,使一个一点不懂中药的人也可以去当抓药师,相反,如果没有这些“封装”呢?
<P>
<P>上一段中我们把对象两字设为黑体,你应该在理解封装的同时明白什么叫对象了:对象就是东西,就是物品,就是事物。不信你把上段中的“对象”替换为“东西”或“物品”,或“事物”是不是读得更顺点?总而言之,面向对象的编程方法其实就是说,让编程的思路尽量符合人们生活中事务处理中已经掌握的科学方法。它并不是牛顿发现地心引力一样的科学探索成果,它只是把已有的科学运用到计算机编程。
<P>
<P>“封装”中草药的方法也许只有一种,而程序所要解决的问题,比区分中草药要复杂得多,所以,如何进行常用数据,行为的封装,也就仁者见仁智者见智。
<P>
<P>VC的MFC和CB的VCL都是基于(但不限于)对Windows
API(应用程序接口函数)的封装。为什么要对API进行封装?这就是回到了我们前面说过的,为什么有了C又会有C++的问题。因为操作系统是用C和汇编写成的,它获得到操作系统必须的代码效率,但对应用程序开发者而言,它失去了易用性。所以微软和Borland都使用高级语言对之进行封装工作。二者谁进行得更好呢?
<P>
<P>VC的封装类库称为MFC,它是一种很低阶的封装,它并没有按照人类的思维习惯来得新组织重新解释Windows对象(指Windows编程中所需的数据,处理,机制,接口),
纯粹是API一对一的翻版。这个的封装工作带来代码封装所固有的代码效率降低的副作用,却没有给使用者带来任何方便。如果你是编程初学者,而你身边又有VC高手,那么你一定要多多向他学习请教,因为一个真正的VC编程高手,其同时一定也是一个深刻理解Windows内核机制(消息循环,内存管理,多任务实现,资源使用等),熟悉Windows各种常用API函数等等的高手。相反,如何一个人对这一些知之不多,而自称为VC高手。你放心,参加了笔者下一级的Windows编程学习,只需2星期,你就会明白那种只会用VC的向导写程序的人是什么样的“高手”了 。
<P>
<P>C++ Builder 对封装库称为VCL(带VC字样,可别以为它是Visual C++,其实它是:Visual Component
Library,即:可视控件库)。
<P>
<P>要想成为Windows编程高手,最终一定要绕过各种封装,理解Windows对象。但作为一个初学者,我们必须挑选一个好的封装。下面我们举字体(Font)作为例子,将三者:没有封装过的Windows
字体API、封装过的MFC字体对象、封装过的VCL字体对象。做一个对比。为了保证不会有偏倚和差错,有关前二者的代码,都是笔者从MSDN(微软提供的帮助文档)中直接拷贝出来。
<P>
<TABLE style="TEXT-ALIGN: left" cellSpacing=0 cellPadding=0 width="100%"
border=0>
<TBODY>
<TR>
<TD style="BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid"
width="18%">Window API</TD>
<TD
style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid"
width="82%"> Windows API创建指定样式字体:
<P>HFONT CreateFont(</P>
<P> int nHeight, // height of font </P>
<P> int nWidth, // average character width </P>
<P> int nEscapement, // angle of escapement </P>
<P> int nOrientation, // base-line orientation angle </P>
<P> int fnWeight, // font weight </P>
<P> DWORD fdwItalic, // italic attribute option </P>
<P> DWORD fdwUnderline, // underline attribute
option </P>
<P> DWORD fdwStrikeOut, // strikeout attribute
option </P>
<P> DWORD fdwCharSet, // character set identifier </P>
<P> DWORD fdwOutputPrecision, // output precision </P>
<P> DWORD fdwClipPrecision, // clipping precision </P>
<P> DWORD fdwQuality, // output quality </P>
<P> DWORD fdwPitchAndFamily, // pitch and family </P>
<P> LPCTSTR lpszFace // typeface name</P>
<P> );</P></TD></TR>
<TR>
<TD style="BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid"
width="18%">MFC (Visual C++)</TD>
<TD
style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid"
width="82%">将HFONT封装为CFont
<P>BOOL CFont::CreateFont (</P>
<P> int nHeight,</P>
<P> int nWidth,</P>
<P> int nEscapement,</P>
<P> int nOrientation,</P>
<P> int nWeight,</P>
<P> BYTE bItalic,</P>
<P> BYTE bUnderline,</P>
<P> BYTE cStrikeOut,</P>
<P> BYTE nCharSet, </P>
<P> BYTE nOutPrecision, </P>
<P> BYTE nClipPrecision, </P>
<P> BYTE nQuality, </P>
<P> BYTE nPitchAndFamily,</P>
<P> LPCTSTR lpszFacename </P>
<P> );</P></TD></TR>
<TR>
<TD
style="BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"
width="18%">VCL (C++ Builder)</TD>
<TD
style="BORDER-RIGHT: 1px solid; BORDER-TOP: 1px solid; BORDER-LEFT: 1px solid; BORDER-BOTTOM: 1px solid"
width="82%">将HFONT封装为TFont1
<P>要设置字体名,高度,尺寸等使用以下代码:</P>
<P> Font->Name = “宋体”; //设置为宋体</P>
<P> Font->Size = 24; //设置尺寸为24号2</P>
<P> </P>
<P>将字体的粗,斜,下划线,删除线再封装为TFontStyle属性:</P>
<P> Font->Style = Font->Style << fsBold <<
fsUnderlien; //字体增加粗体和下划线属性。</P>
<P> </P>
<P>对于字体不常用的旋转等属性,不进行封装,你可以直接调用API函数来设置TFont的
Handle属性。</P></TD></TR></TBODY></TABLE>
<P>比较表中第一行和第二行:前者是原始的API,后者是VC精心的封装成果。可惜二者几近雷同。既然你要封装,你就是要让它变得面向对象,易记易用;一模一样的照抄一遍,然后改改参数的名字,意义何在?如你是想维持代码的效率,那么在繁杂度一样的情况下,为什么我不直接使用效率更高的API函数呢?</P>
<P> </P>
<P>倘若说,MFC的“封装”纯粹是一种多余,那或许也还可以接受。然而MFC偏偏还要在这种冗余的封装上建立自已的应用程序架构。和前面的“封装”一样,MFC建立应用架构的出发点也是良好的,为了方便Windows程序员编程的难度。结果却更糟糕。有问题的架构犯了类库或接口提供者的大忌:“有协议编程”。
</P>
<P> </P>
<P>什么叫“有协议编程”?我们先来讲“无协议编程”。所谓“无协议编程”是指接口的提供者在提供接口时,同时也提供接口的使用约定。这一套约定应该在接口所要提供的功能上广泛适用,而无须再有种种特殊的例外。这样的接口显然非常适于使用。打个比方就如交通规则。“红灯停绿灯”行应该是普遍适用的规则,如果在红灯停绿灯行还附加以下例外条款:<BR></P>
<P>1、 单号并且在阴天下东行的路面上红灯行绿灯停; </P>
<P> </P>
<P>2、 轿车在乘客人数为奇数的情况下见红灯允许直行但不能右拐; </P>
<P> </P>
<P>3、 日间12点到14点区间并且街心交警为女性时,红灯停或行临时取决于女警的身高是否高于1米70…… </P>
<P> </P>
<P>尽管这些例外都是一些不常见的情况,但想像一下你自已是这种制度下生存的司机吧。学习编程,如果挑错了我们每天都要面对的封装类库。就将永远都在努力处理这些无任何意义的问题。和司机不同的是你倒不会有多难受——一个人陷在泥潭中久了,往往就会认为自已挣扎的动作优美得堪称艺术。
</P>
<P> </P>
<P>MFC的CWnd 提供了对Windows最基本的窗口元素的封装,其中对创建窗口的函数的封装为: </P>
<P> </P>
<P>未封装的API: </P>
<P> </P>
<P>HWND CreateWindow(</P>
<P>LPCTSTR lpClassName, // registered class name</P>
<P>LPCTSTR lpWindowName, // window name</P>
<P>DWORD dwStyle, // window style</P>
<P>int x, // horizontal position of window</P>
<P>int y, // vertical position of window</P>
<P>int nWidth, // window width</P>
<P>int nHeight, // window height</P>
<P>HWND hWndParent, // handle to parent or owner window</P>
<P>HMENU hMenu, // menu handle or child identifier</P>
<P>HINSTANCE hInstance, // handle to application instance</P>
<P>LPVOID lpParam // window-creation data</P>
<P>); </P>
<P></P>
<P>使用这个API函数,我们可以创建各种窗口。 </P>
<P> </P>
<P>CWnd封装的函数: </P>
<P> </P>
<P>virtual BOOL CWnd::Create (<BR> LPCTSTR
lpszClassName, <BR> LPCTSTR
lpszWindowName, <BR> DWORD
dwStyle, <BR> const RECT&
rect, <BR> CWnd* pParentWnd, <BR>
UINT nID, <BR> CCreateContext* pContext =
NULL<BR> ); </P>
<P> </P>
<P>不用我说,你也能看出这仍然是个改改参数的蹩脚的封装。我们不去管它,现在我们关心的是:CWnd::Create 对 CreateWindow
进行了封装,可是这一封装的结果是:原来CreateWindow能实现的一些事情,在
CWnd::Create里突然成了例外。是的,为了适应CWnd在MFC架构中所处的角色,程序员在涉及CWnd时必须记忆这样一条例外:<BR></P>
<P>“CWnd的Create用于创建窗口的实际元素,但其中参数dwStyle不能包含有窗口风格中WS_POPUP(弹出式窗口),如果你要建立一个带有该风格的窗口,请使用CreateEx……”<BR><BR></P>
<P>……<BR><BR></P>
<P>我仍然要说VC也是一个很优秀的编程工具,但对于不想浪费无谓精力的编程初学者,我个人建议使用Borland C++
Builder,因为它实现真正的对象封装,从而,你可以节省不低于80%的时间来学习编程本质的知识——就是我们常说的数据结构与算法,这些东西最终决定你的编程能力。<BR><BR></P>
<P>这就是C++ Builder提供我们的最重要的东西:<BR><BR></P>
<P>VCL类库:一个好的底层类库,让我们从学习编程最初时刻就自然而然地学会使用面向对象的方法来写程序。它大大降低了我们入门门槛的高度,却又让我们一开始就站在比别人高的位置看待有程序有关的问题;<BR><BR></P>
<P>组件技术:组件技术代表了当今编程技术的主要方向,其设计思想与MS力推的Active
控件如出一辙,拥有相同的先进性。只有借助组件技术,我们才有可能从一个初学者,迅速到达可实际工作的编程工作者;另一方面,如果作为组件的提供者,我们可以编写组件的过程中迅速提高自已的编程能力。
</P>
<P> </P>
<P>C++
Builder还提供了许多其它先进技术,如事件委拖等等,归根到底都通过封装让Windows编程原本需要长期积累的才有可能掌握的知识变得直观易懂。如果你刚刚开始学习编程,或者学习较长时间仍没有重大突破。或许使用C++
Builder结合本课程系列,是个不错的选择。 </P>
<P> </P>
<P>(附言:微软最近推出的C#相信会对上述MFC的不足做一个收拾,它对C++的扩展与约束与Borland C++ Builder
对C++的扩展与约束惊人的相似。如果你乐意,我也真的很建议你在学完C++
Builder后,继续学习C#)<BR></P></TD></TR></TBODY></TABLE></CENTER>
<P align=center>[<A
href="http://d2school.com/bcyl/bhcpp/newls/ls01.htm#页首">到页首</A>]</P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -