认识 Delphi 构造函数中的关键字:virtual、override、overload、reintroduce

欢迎加入全网最大Delphi 技术交流群 682628230

 在Delphi中,构造函数的声明和继承行为可能会让人感到困惑,尤其是当涉及到virtualoverrideoverload reintroduce这些关键字时。本文将通过一个具体的类层次结构示例,解释这些关键字的正确使用方式及其背后的逻辑。

示例类层次结构

假设我们有以下类层次结构:
 
TComputer = class(TObject)
public
    constructor Create(Cup: Integer); virtual;
end;

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); overload; override;
    constructor Create(Cup: Integer; Teapot: string); override;
end;

关键字的含义

  1. virtual
    • 用于声明一个方法可以在派生类中被覆盖(override)。virtual关键字只能用于方法的首次声明。
    • 在构造函数中使用virtual允许派生类覆盖该构造函数。
  2. override
    • 用于覆盖基类中的virtual方法。override关键字只能用于派生类中,且被覆盖的方法必须与基类中的方法具有相同的签名。
  3. overload
    • 用于声明多个同名方法,但参数列表不同。overload关键字必须用于所有重载方法的声明。
    • 当一个类中有多个同名构造函数时,必须使用overload
  4. reintroduce
    • 用于显式隐藏基类中的同名方法。reintroduce关键字用于声明一个新的方法,该方法与基类中的方法同名,但不覆盖它。
    • 使用reintroduce时,通常需要结合overload来避免编译器警告。

示例类的正确声明方式

  1. TComputer
    • 声明一个virtual构造函数,允许派生类覆盖它。
     
    TComputer = class(TObject)
    public
        constructor Create(Cup: Integer); virtual;
    end;
  2. TCellPhone
    • 声明一个新的构造函数,与基类中的构造函数同名但参数不同。
    • 使用reintroduceoverload来显式隐藏基类中的构造函数,并声明新的构造函数。
    • 使用virtual允许派生类覆盖该构造函数。
     
    TCellPhone = class(TComputer)
    public
        constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
    end;
  3. TiPhone
    • 覆盖基类中的两个构造函数。
    • 使用override覆盖基类中的virtual构造函数。
    • 使用overload声明新的构造函数。
     
    TiPhone = class(TCellPhone)
    public
        constructor Create(Cup: Integer); overload; override;
        constructor Create(Cup: Integer; Teapot: string); override;
    end;

关键字的顺序

根据Delphi的文档,方法声明中的关键字顺序如下:
  1. reintroduce
  2. overload
  3. bindingvirtualdynamicoverride
  4. calling conventionregisterpascalcdeclstdcallsafecall
  5. abstract
  6. warningplatformdeprecatedlibrary

示例代码的运行结果

以下是完整的示例代码及其运行结果:
 
program OnConstructors;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TComputer = class(TObject)
  public
    constructor Create(Cup: Integer); virtual;
  end;

  TCellPhone = class(TComputer)
  public
    constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
  end;

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); overload; override;
    constructor Create(Cup: Integer; Teapot: string); override;
  end;

{ TComputer }

constructor TComputer.Create(Cup: Integer);
begin
  Writeln('Computer: cup = ', Cup);
end;

{ TCellPhone }

constructor TCellPhone.Create(Cup: Integer; Teapot: string);
begin
  inherited Create(Cup);
  Writeln('Cellphone: teapot = ', Teapot);
end;

{ TiPhone }

constructor TiPhone.Create(Cup: Integer);
begin
  inherited Create(Cup);
  Writeln('iPhone: cup = ', Cup);
end;

constructor TiPhone.Create(Cup: Integer; Teapot: string);
begin
  inherited;
  Writeln('iPhone: teapot = ', Teapot);
end;

var
  C: TComputer;

begin
  C := TComputer.Create(1);
  Writeln; FreeAndNil(C);

  C := TCellPhone.Create(2);
  Writeln; FreeAndNil(C);
  C := TCellPhone.Create(3, 'kettle');
  Writeln; FreeAndNil(C);

  C := TiPhone.Create(4);
  Writeln; FreeAndNil(C);
  C := TiPhone.Create(5, 'iPot');

  Readln; FreeAndNil(C);
end.
运行结果:
 
Computer: cup = 1

Computer: cup = 2

Computer: cup = 3
Cellphone: teapot = kettle

Computer: cup = 4
iPhone: cup = 4

Computer: cup = 5
Cellphone: teapot = iPot
iPhone: teapot = iPot

 

  • 在Delphi中,构造函数可以使用virtualoverrideoverloadreintroduce关键字来控制其继承和覆盖行为。
  • 使用virtualoverride时,构造函数必须具有相同的签名。
  • 使用overload时,构造函数可以具有不同的参数列表。
  • 使用reintroduce时,需要显式隐藏基类中的同名方法。
  • 关键字的顺序必须遵循Delphi的文档规范。
通过正确使用这些关键字,可以灵活地设计类的构造函数,满足复杂的继承需求。
© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享