delphi 面向对象
delphi 面向对象学习
- TObject -- 所有类的基类
TObject = class
//默认是private类型的静态方法
constructor Create; //静态方法不能被重写
procedure Free;//静态方法不能被重写
class function InitInstance(Instance: Pointer): TObject;
procedure CleanupInstance;
function ClassType: TClass;
class function ClassName: ShortString;
class function ClassNameIs(const Name: string): Boolean;
class function ClassParent: TClass;
class function ClassInfo: Pointer;
class function InstanceSize: Longint;
class function InheritsFrom(AClass: TClass): Boolean;
class function MethodAddress(const Name: ShortString): Pointer;
class function MethodName(Address: Pointer): ShortString;
function FieldAddress(const Name: ShortString): Pointer;
function GetInterface(const IID: TGUID; out Obj): Boolean;
class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
class function GetInterfaceTable: PInterfaceTable;
function SafeCallException(ExceptObject: TObject;
ExceptAddr: Pointer): HResult; virtual;
procedure AfterConstruction; virtual;
procedure BeforeDestruction; virtual;
procedure Dispatch(var Message); virtual;
procedure DefaultHandler(var Message); virtual;
class function NewInstance: TObject; virtual;
procedure FreeInstance; virtual;
//private不能被override( Method 'Destory' not found in base class)
//之所以还要加virtual,是为了在派生类VMT中保留方法指针
destructor Destroy; virtual;
end;
//类方法
class function TObject.ClassName: ShortString;
{$IFDEF PUREPASCAL}
begin
Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
end;
{$ELSE}
asm
{ -> EAX VMT }
{ EDX Pointer to result string }
PUSH ESI
PUSH EDI
MOV EDI,EDX
MOV ESI,[EAX].vmtClassName
XOR ECX,ECX
MOV CL,[ESI]
INC ECX
REP MOVSB
POP EDI
POP ESI
end;
{$ENDIF}
- class 标志方法为类方法,无需实例化即可调用
- constructor Create; 默认构造器
- destructor Destroy; virtual; 默认析构器
- dynamic; virtual; abstract
dynamic h和 virtual 是定义多态方法的2中形式,dynamic 方法在DMT表中, virtual 方法在VMT表中,
每个类都会有自己的VMT/DMT表 在使用上面是一样的, 区别是:
dynamic方法: DMT表不会随着类的派生而增加(如果子类没有覆盖dynamic方法则不会有DMT表,那么需要去父类DMT表中查找-调用)节省DMT表空间, 但是查找-调用效率不如virtual方法. ---- 空间占优
virtual方法: 每个派生类VMT表都会包含父类virtual方法指针和自己的virtual方法, 多子类/多重继承VMT表会很占空间,但是因为每个类VMT表包含所有Virtual方法,不需要去找父类VMT, 查找-调用virtual方法比dynamic方法快. ---- 时间占优
-
Unit1
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls ; type TForm1 = class(TForm) test3: TButton; Memo1: TMemo; test1: TButton; test2: TButton; test4: TButton; procedure test3Click(Sender: TObject); procedure test1Click(Sender: TObject); procedure test2Click(Sender: TObject); procedure Memo1DblClick(Sender: TObject); procedure test4Click(Sender: TObject); private { Private declarations } procedure WndProc(var msg:TMessage); override; public { Public declarations } procedure writeLog(sLog: string); end; var Form1: TForm1; implementation uses Unit2; {$R *.dfm} procedure TForm1.writeLog(sLog: string); begin Memo1.Lines.Add(FormatDateTime('yyyy-MM-dd hh:nn:ss.zzz', Now) + ' ' + sLog); end; procedure TForm1.test1Click(Sender: TObject); var base: TBase; test: TTest; obj: TObject; begin //如果派生类没有显示inherited父类构造/析构函数,则只会调用派生类自定义的构造/析构函数,或者TObject的。 writeLog('base := TBase.Create'); base := TBase.Create; writeLog('test := TTest.Create'); test := TTest.Create; writeLog('obj := TTest.Create'); obj := TTest.Create; writeLog('base.s = ' + base.s + ' base.s1 =' + base.s1); writeLog('test.s = ' + test.s + ' test.s1 =' + test.s1 + ' test.s2 = ' + test.s2); writeLog('TBase(obj).s = ' + TBase(obj).s + ' TBase(obj).s1 =' + TBase(obj).s1); writeLog('TTest(obj).s = ' + TTest(obj).s + ' TTest(obj).s1 =' + TTest(obj).s1 + ' TTest(obj).s2 = ' + TTest(obj).s2); test.FrendClass; writeLog('FreeAndNil(base)'); FreeAndNil(base); writeLog('FreeAndNil(test)'); FreeAndNil(test); writeLog('FreeAndNil(obj)'); FreeAndNil(obj); end; procedure TForm1.test2Click(Sender: TObject); var base: TBase; test: TTest; obj: TObject; p1, p2, p3: Pointer; begin writeLog('base := TBase.Create'); base := TBase.Create; writeLog('test := TTest.Create'); test := TTest.Create; writeLog('obj := TTest.Create'); obj := TTest.Create; p1 := PChar(base.s); writeLog('base.s = ' + string(p1)); p2 := PChar(test.s); writeLog('test.s = ' + string(p2)); p3 := PChar(TTest(obj).s2); writeLog('obj.s2 = ' + string(p3)); writeLog('FreeAndNil(base)'); FreeAndNil(base); writeLog('FreeAndNil(test)'); FreeAndNil(test); writeLog('FreeAndNil(obj)'); FreeAndNil(obj); //报错 空指针 try writeLog('base.s = ' + string(p1)); writeLog('test.s = ' + string(p2)); writeLog('obj.s = ' + string(p3)); except on e: Exception do ShowMessage(e.message); end; end; procedure TForm1.test3Click(Sender: TObject); var base: TBase; test: TTest; obj: TObject; begin writeLog('base := TBase.Create'); base := TBase.Create; writeLog('test := TTest.Create'); test := TTest.Create; writeLog('obj := TTest.Create'); obj := TTest.Create; writeLog('test.s = ' + test.s + ' test.s1 =' + test.s1 + ' test.s2 = ' + test.s2); writeLog('TBase before Free: ' + IntToStr(Integer(base))); writeLog('TTest before Free: ' + IntToStr(Integer(test))); writeLog('TObject before Free: ' + IntToStr(Integer(obj))); //通过TObject.free 调用 Destroy 因为Destroy是virtual,会调用自己的VMT函数。可能是 //如果TTest未定义Destroy,那么调用的是TObject.Destroy //如果TTest已定义Destroy,则等价于TTest.Destroy; writeLog('base.Free:'); base.Free; writeLog('test.Free:'); test.Free; //不管派生类test是否定义free,调用的是TObject.free,因为free非virtual //obj.Free 和 TTest(obj).Free 区别 // writeLog('obj.Free:'); // obj.Free; //要调用test.free,必须显示调用TTest(obj).Free; writeLog('TTest(obj).Free:'); TTest(obj).Free; //对象释放,但是指针还指向它的地址 writeLog('TBase after Free: ' + IntToStr(Integer(base))); writeLog('TTest after Free: ' + IntToStr(Integer(test))); writeLog('TObject after Free: ' + IntToStr(Integer(obj))); end; procedure TForm1.Memo1DblClick(Sender: TObject); begin Memo1.Lines.Clear; end; procedure TForm1.test4Click(Sender: TObject); var mmStream: TMemoryStream; sFileName: string; begin //序列化窗体、组件 sFileName := ExtractFilePath(ParamStr(0)) + self.Name + '.txt'; mmStream := TMemoryStream.Create; mmStream.WriteComponent(Self); mmStream.SaveToFile(sFileName); writeLog(sFileName); end; procedure TForm1.WndProc; begin inherited; //重定义窗体消息处理过程 end; end.
-
Unit2
unit Unit2; interface uses Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, StdCtrls; type TBase = class // 等价于 TBase = class(TObject) public //便于显示设置未可见 s: string; s1: string; // procedure Free; override; // Cannot override a static method TObject.Free // procedure Free; //重定义Free static 不可被重写 procedure Free; virtual; //重定义Free 可被重写 // constructor Create(); //显示定义构造器,不使用默认的TObject.create,默认静态不能被派生类重写 // destructor Destory(); //显示定义析构器,不使用默认的TObject.Destory,默认静态不能被派生类重写 constructor Create(); virtual; //virtual显示定义构造器,可被派生类重写 destructor Destory(); virtual; //virtual显示定义构造器,可被派生类重写 // constructor Create(); override; // Cannot override a static method // destructor Destory(); override; //TObject.Destory虽可被重写,但不可见: Method 'Destory' not found in base class end; {同一个单元定义的类互为友元类,可以互相访问private域, 否则TBase.s1为私有时TTest.s1报错:不可见} TTest = class(TBase) public //便于显示设置未可见 s: string; //属性同名使用TTest.s 非 TBase.s ;不同名TTest.s1是 TBase.s1 s2: string; procedure Free; override; constructor Create(); override; destructor Destory(); override; procedure FrendClass; end; implementation uses Unit1; { TBase } constructor TBase.Create; begin inherited; //必须显示调用父类构造函数 Self.s := 'TBase.s'; Self.s1 := 'TBase.s1'; Form1.writeLog('执行的是:TBase.Create'); end; destructor TBase.Destory; begin Form1.writeLog('执行的是:TBase.Destory'); inherited; //必须显示调用父类析构函数 end; procedure TBase.Free; begin Form1.writeLog('执行的是:TBase.Free'); Destory; end; { TTest } constructor TTest.Create; begin inherited; //必须显示调用父类构造函数 Self.s2 := 'TTest.s2'; Form1.writeLog('执行的是:TTest.Create'); end; destructor TTest.Destory; begin Form1.writeLog('执行的是:TTest.Destory'); inherited; //必须显示调用父类析构函数 end; procedure TTest.Free; begin Form1.writeLog('执行的是:TTest.Free'); destory; end; procedure TTest.FrendClass; begin Form1.writeLog('执行的是:TTest.FrendClass'); {同一个单元定义的类互为友元类,可以互相访问private域, 否则TBase.s1为私有时Self.s1报错:不可见} Form1.writeLog('TTest.s=' + Self.s + ' ;' + 'TTest.s1=' + Self.s1 + ' ;' + 'TTest.s2=' + Self.s2); end; end.
-
运行结果