<<深入核心VCL架构剖析>>笔记(2)

构造函数(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:相应鼠标事件,控制光标,分派事件消息.具有可持久化的基本信息,如位置等.控制格式,如颜色,字体等信息.

原文地址:https://www.cnblogs.com/cxp2009/p/2277124.html