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

  • 相关阅读:
    FCN网络
    YOLO学习
    图像的几何变换-仿射变换和透射变换
    图像处理中的插值方法
    opencv中imgshow图像显示为灰色
    JDBC开发,数据库的连接
    Object类和String类
    动态线条,随鼠标移动吸附效果
    匿名对象,内部类,包,访问修饰符,代码块
    final关键字,static关键字
  • 原文地址:https://www.cnblogs.com/cxp2009/p/2277124.html
Copyright © 2020-2023  润新知