本人在OOP方面刚刚入门,只是看过一些国外这方面的好材料,才萌生了写本文的念头。希望能够起到抛砖引玉的作用,引出高手们的批评和建议。
OOP和面向过程都是编程中的思想,用学术一些的话是paradigm。曾经有人说过,既然cfront生成的是C代码,那么用C本身乃至汇编都可以实现OOP,只是太多东西需要自己手工来完成。确实是这样的,面向过程早就用在汇编设计中了,OOP也早就和汇编有了交汇点(95年之前,TASM就引入了OOP的概念)。只是汇编实现OOP是没有形式上的,无法提供C++这样的Strong-typed和其他安全保证(比如存取权限)。封装只是一种概念上的,自觉遵守的。
OOP有几个关键,据我的粗浅理解即为:封装性,继承与多态。具体表现就是把数据和操作数据的函数放在一起,数据放在对象中,提供接口实现存取。继承性实现了语义或者实现的继承,同时体现在概念层次与代码重用两个方面。多态则是利用指针实现使用pointer或reference来实现同一函数在不同继承类中的多态表现。
OOP的对象模型有好几种实现方式,在《inside C++ object model》中有极其详尽的叙述:
1.只把数据放在对象中,而通过name mangling技术把member-function与class关联起来。 2.单表模型,把member function的pointer放入到单独的一个表格,把表格的入口地址放入对象中(一个类对应一个表格)。这在C++中表现为Vtbl与Vptr,这种模型实现了运行时的动态灵活性,虽然多了两次dereference。 3.双表模型,把数据与函数分列在两个表格中,然后把两个表格的入口地址存放在对象中,使得单个对象有了固定的大小。 4.简单模型,这个是汇编实做的时候用的模型。就是对象中即保存了数据也保存了函数地址。无论是TASM还是MASM,都是这么做的。从效能上来说,C++的做法是最优的。汇编使用第四种是迫不得已,是为了实现的简单性。一定程度上与汇编的高效的精神违背。
TASM已经不常用了,其OOP的做法和MASM的做法也是类似的。这里主要讨论MASM的OOP做法。作者是NaN 和Thomas Bleeker。其实现的办法是用宏定义来达到本来应该是编译器做的幕后工作。其中的宏的技巧很多。但是最终的使用是挺简单的。宏的定义放在一个OBJECTS.INC的文件中,asm文件包含这个inc就能使用这个object model。
虽然宏做得很精巧,但是毕竟MASM缺少支持OOP的语法特性,在使用的很多方面都有麻烦或者在空间时间上有代价。比如覆盖基类的虚函数必须每次手工的完成。也就是继承的层次中所有父类以上的被覆盖的虚函数都需要在子类中手工完成。虽然是有这样那样的缺点,但是OOP还是给汇编带来了不少好处。比如:
1.汇编更好的和COM,C++这样的面向对象领域的东西互动。已经有用汇编+OOP调用com的例子。如果用汇编+OOP来写com将可以产生适合高速度和小尺寸的组件。 2.扩大了汇编能够解决的问题范围,使得汇编程序更加容易管理和合作编写。这个object model的作者就用汇编+OOP写了一个基于神经网络的手写字母识别的程序,不到200k(其中大部分是图象文件占用的空间)。 使用定义一个基类的办法。
;准备好函数原型 Shape_Init PROTO :DWORD Shap_destructorPto TYPEDEF PROTO :DWORD Shap_getAreaPto TYPEDEF PROTO :DWORD Shap_setColorPto TYPEDEF PROTO :DWORD, :DWORD ;实际上就是STRUC的定义 CLASS Shape, Shap CMETHOD destructor CMETHOD getArea CMETHOD setColor Color dd ? Shape ENDS .data ;初始化 BEGIN_INIT dd offset Shap_destructor_Funct dd offset Shap_getArea_Funct dd offset Shap_setColor_Funct dd NULL END_INIT .code Shape_Init PROC uses edi esi lpTHIS:DWORD ;实际调用初始化 SET_CLASS Shape ;把edi assmue 为Shape类型 SetObject edi, Shape ;额外定义的DPrint宏,不用细究 DPrint "Shape Created (Code in Shape.asm)" ;取消assmue ReleaseObject edi ret Shape_Init ENDP Shap_destructor_Funct PROC uses edi lpTHIS:DWORD SetObject edi, Shape DPrint "Shape Destroyed (Code in Shape.asm)" ReleaseObject edi ret Shap_destructor_Funct ENDP Shap_setColor_Funct PROC uses edi lpTHIS:DWORD, DATA:DWORD SetObject edi, Shape mov eax, DATA mov [edi].Color, eax DPrint "Shape Color Set!! (Code in Shape.asm)" ReleaseObject edi ret Shap_setColor_Funct ENDP Shap_getArea_Funct PROC uses edi lpTHIS:DWORD SetObject edi, Shape DPrint " " DPrint " SuperClassing!!!!! This allows code re-use if you use this method!!" DPrint " Shape's getArea Method! (Code in Shape.asm)" mov eax, [edi].Color DPrint " Called from Shape.getArea, (Code in Shape.asm)" DPrintValH eax, " This objects color val is" DPrint " " ReleaseObject edi ret Shap_getArea_Funct ENDP
继承这个类
include Shape.asm ; Inherited class info file Circle_Init PROTO :DWORD Circ_destructorPto TYPEDEF PROTO :DWORD Circ_setRadiusPto TYPEDEF PROTO :DWORD, :DWORD Circ_getAreaPto TYPEDEF PROTO :DWORD CLASS Circle, Circ ;继承原有的数据和函数 Shape ; Inherited Class CMETHOD setRadius Radius dd ? Circle ENDS .data BEGIN_INIT dd offset Circ_destructor_Funct dd offset Circ_setRadius_Funct dd NULL END_INIT .code Circle_Init PROC uses edi esi lpTHIS:DWORD ;初始化并实现继承 SET_CLASS Circle INHERITS Shape SetObject edi, Circle ;相当于构造函数重置vptr OVERRIDE getArea, CirleAreaProc DPrint "Circle Created (Code in Circle.asm)" ReleaseObject edi ret Circle_Init ENDP Circ_destructor_Funct PROC uses edi lpTHIS:DWORD SetObject edi, Circle DPrint "Circle Destroyed (Code in Circle.asm)" ;实现了基类函数的调用 SUPER destructor ReleaseObject edi ret Circ_destructor_Funct ENDP Circ_setRadius_Funct PROC uses edi lpTHIS:DWORD, DATA:DWORD SetObject edi, Circle mov eax, DATA mov [edi].Radius, eax DPrint "Circle Radius Set (Code in Circle.asm)" ReleaseObject edi ret Circ_setRadius_Funct ENDP CirleAreaProc PROC uses edi lpTHIS:DWORD LOCAL TEMP SetObject edi, Circle SUPER getArea mov eax, [edi].Radius mov TEMP, eax finit fild TEMP fimul TEMP fldpi fmul fistp TEMP mov eax, TEMP DPrint "Circle Area (integer Rounded) (Code in Circle.asm)" ReleaseObject edi ret CirleAreaProc ENDP
根据类来生成对象,并使用
DEBUGC equ 1 .586 .model flat,stdcall option casemap:none include \masm32\include\windows.inc include \masm32\include\masm32.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\masm32.lib include Dmacros.inc include Objects.inc include Circle.asm .data .data? hCircle dd ? .code start: ; Recuse all inherited constructors.. and do all inits DPrint " " DPrint " >>> main.asm > main.asm > main.asm > main.asm > main.asm > main.asm
本文地址:http://com.8s8s.com/it/it29382.htm