构造函数(constructor或ctor):分配内存,初始化资源
析构函数(destructor或dtor):释放内存,执行初始化反向工作(释放资源)
TObject.NewInstance:分配内存并进行初始化.
动态方法(dynamic):节约VMT空间,但速度低于虚拟方法(virtual)
Delphi对象分配机制是使用用堆分配(Heap Allocation),而C/C++可以同时使用堆分配和栈分配(Stack Allocation).这个意思是说当程序员声明如下代码时:
var aObj: TBase; begin ...
此代码只是定义了TBase类型的一个对象指针,并没有实际分配物理内存.必须使用对象创建服务才会让对象在内存中形成.
而C/C++声明如下代码时:
void... { TBase aObj; }
aObj已经在堆栈中形成了实体对象.
和释放服务有关的函数有:
Destroy,Free,FreeInstance,CleanupInstance.
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
CleanupInstance:负责释放类分配的特别数据类型变量的空间.什么是特别数据类型呢,从_FinalizeArray函数里可以看出,特别数据类型包括:字符串数组,variant(变体),array(未定义类型数组),record(记录),Interface(接口),DynArray(动态数组)
procedure _ClassDestroy(Instance: TObject);
begin
Instance.FreeInstance;
end;
procedure TObject.FreeInstance;
begin
CleanupInstance;
_FreeMem(Self);
end;
procedure TObject.CleanupInstance;
{$IFDEF PUREPASCAL}
var
ClassPtr: TClass;
InitTable: Pointer;
begin
ClassPtr := ClassType;
repeat
InitTable := PPointer(PByte(ClassPtr) + vmtInitTable)^;
if InitTable <> nil then
_FinalizeRecord(Self, InitTable);
ClassPtr := ClassPtr.ClassParent;
until ClassPtr = nil;
TMonitor.Destroy(Self);
end;
function _FinalizeRecord(P: Pointer; TypeInfo: Pointer): Pointer;
var
FT: PFieldTable;
I: Cardinal;
begin
FT := PFieldTable(PByte(TypeInfo) + Byte(PTypeInfo(TypeInfo).Name[0]));
if FT.Count > 0 then
begin
for I := 0 to FT.Count - 1 do
_FinalizeArray(Pointer(PByte(P) + IntPtr(FT.Fields[I].Offset)), FT.Fields[I].TypeInfo^, 1);
end;
Result := P;
end;
function _FinalizeArray(P: Pointer; TypeInfo: Pointer; ElemCount: NativeUInt): Pointer;
var
FT: PFieldTable;
begin
Result := P;
if ElemCount = 0 then Exit;
case PTypeInfo(TypeInfo).Kind of
tkLString: _LStrArrayClr(P^, ElemCount);
tkWString: _WStrArrayClr(P^, ElemCount);
tkUString: _UStrArrayClr(P^, ElemCount);
tkVariant:
while ElemCount > 0 do
begin
_VarClr(PVarData(P)^);
Inc(PByte(P), SizeOf(TVarData));
Dec(ElemCount);
end;
tkArray:
begin
FT := PFieldTable(PByte(typeInfo) + Byte(PTypeInfo(typeInfo).Name[0]));
while ElemCount > 0 do
begin
_FinalizeArray(P, FT.Fields[0].TypeInfo^, FT.Count);
Inc(PByte(P), FT.Size);
Dec(ElemCount);
end;
end;
tkRecord:
begin
FT := PFieldTable(PByte(TypeInfo) + Byte(PTypeInfo(TypeInfo).Name[0]));
while ElemCount > 0 do
begin
_FinalizeRecord(P, TypeInfo);
Inc(PByte(P), FT.Size);
Dec(ElemCount);
end;
end;
tkInterface:
while ElemCount > 0 do
begin
_IntfClear(IInterface(P^));
Inc(PByte(P), SizeOf(Pointer));
Dec(ElemCount);
end;
tkDynArray:
while ElemCount > 0 do
begin
{ The cast and dereference of P here is to fake out the call to
_DynArrayClear. That function expects a var parameter. Our
declaration says we got a non-var parameter, but because of
the data type that got passed to us (tkDynArray), this isn't
strictly true. The compiler will have passed us a reference. }
_DynArrayClear(PPointer(P)^, typeInfo);
Inc(PByte(P), SizeOf(Pointer));
Dec(ElemCount);
end;
else
Error(reInvalidPtr);
end;
end;
以上内容一般情况都不需要程序员涉及,程序员要做的就是override Destroy;
Self---->ClassType---->VMT;(---->指向的意思)
Delphi允许创建抽象类对象,这会导致执行时期错误.虽然在语法上是合法的.
抽象类已经逐渐被接口设计取代.
Place Holder方法:父类的一些虚拟方法被实现为空白而不声明为抽象方法.避免了抽象类的缺点.
逐渐增加法: 父类提供基础实现,再由派生类提供更多的实现.
三明治手法:派生类改写父类的方法时,会在使用inherited前加入一些派生类的代码,再使用inherited调用父类方法,最后再加入一些派生类的实现,如:
......{派生类方法}
inherited;{调用父类方法}
......{派生类方法}
使用三明治手法通常是为了派生类在使用inherited前改变对象的状态.
覆写父类实现法:完全不使用父类的方法.
BootStrap设计法:
function TObject.FieldAddress(const Name: ShortString): Pointer;
获得对象指定属性名称的访问地址指针。(当从tool palette拖放一个button到form1上,会在form1上自动添加Button1: TButton,于是可以通过form1.FieldAddress('Button1')得到button1的访问地址指针)
VCL的三个核心类:
TObject:提供了VCL的基础服务.
TPersistent:提供了VCL持久化的能力.
TComponent:所有VCL组件类的基类.VCL组件的设计使用了Container的概念,即VCL组件可包含子VCL组件.TComponent提供了如下的基础服务:
1.作为基础的根组件类.
2.可同时扮演Container组件和单一组件的功能.
3.基础组件管理功能.
4.基础组件互动通知动能(Notification)
5.同时提供可视化和非可视化组件架构基础.
constructor TComponent.Create(AOwner: TComponent);
begin
FComponentStyle := [csInheritable];
if AOwner <> nil then AOwner.InsertComponent(Self);
end;
InsertComponent是TComponent提供的基础组件管理功能之一,其功能是将TComponent所拥有的对象都加入它列表里(FComponents),
procedure TComponent.InsertComponent(AComponent: TComponent);
begin
AComponent.ValidateContainer(Self);
if AComponent.FOwner <> nil then
AComponent.FOwner.RemoveComponent(AComponent);//将obj从以前的owner列表里删除
ValidateRename(AComponent, '', AComponent.FName);//检查obj名称是否合法(是否和已有的组件名称相同)
Insert(AComponent);//将obj加入到owner的列表里
AComponent.SetReference(True);//将owner对应的对象属性指针指向obj
if csDesigning in ComponentState then
AComponent.SetDesigning(True);//添加csDesigning状态到obj及其所拥有的子控件
Notification(AComponent, opInsert);//广播obj的出现
end;
destructor TComponent.Destroy;
begin
Destroying;//添加csDestroying状态到obj及其所拥有的子子子..控件
RemoveFreeNotifications;//遍历FFreeNotifies,向子子子组件发送opRemove通知,将Component从子子子....组件的FFreeNotifies里删除,还把子子子...组件从FFreeNotifies里删除.
DestroyComponents;//遍历FComponents,向子子子组件发送opRemove通知,将Component从子子子....组件的FComponents里删除,还把子子子...组件从FComponents里删除
if FOwner <> nil then FOwner.RemoveComponent(Self);//从拥有者那里将自己删除.
FObservers.Free;
inherited Destroy;//释放资源
end;
改写procedure CreateParams(var Params: TCreateParams); virtual;可以控制窗体的特征.例如:
TForm2 = class(TForm)
......
public
......
procedure CreateParams(var Params: TCreateParams); override;
end;
......
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.X := 0; //Left
Params.Y := 0; //Top
Params.Caption := PChar(Format('%s %s' , [Params.WinClassName,DateTimeToStr(Now)])); //Caption
end;
TControl:相应鼠标事件,控制光标,分派事件消息.具有可持久化的基本信息,如位置等.控制格式,如颜色,字体等信息.