为什么在“重载”方法中将参数类型从“ const”切换为“ var”时无法传递“ Child”类实例

Nas*_*out 5 delphi delphi-10.2-tokyo

MCVE:

从切换参数类型时下面的代码不与错误编译constvarout在重载方法Train的类的TAnimalTrainer

但如果指定为non,则会编译。

[dcc32错误] Project14.dpr(41):E2250没有可使用这些参数调用的“火车”的重载版本

program Project14;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type    
  TAnimal = class
  private
  FName: string;   
  end;

  TDog = class(TAnimal)
  public
    constructor Create(Name: string);
  end;

  TAnimalTrainer = record // class or record
  public
    procedure Train({const}var aA: TAnimal); overload; // class method or not
    procedure Train(const aName: string); overload;
  end;

{ TAnimalTrainer }

procedure TAnimalTrainer.Train(const aName: string);
var
  Dog: TDog;
begin
  Dog := nil;
  try
    Dog := TDog.Create(aName);  
    Train(Dog); // error here
  finally
    Dog.Free;
  end;
end;

procedure TAnimalTrainer.Train(var aA: TAnimal);
begin
  aA := nil;
end;

{ TDog }

constructor TDog.Create(Name: string);
begin
  FName := Name;
end;



begin
  try       
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
Run Code Online (Sandbox Code Playgroud)

找到的解决方法:

  • 省略var
  • 将局部变量强制转换为 TAnimal(Dog)
  • 坚持const

问题:这是编译器中的错误吗?

Dav*_*nan 8

这是编译器中的错误吗?

不它不是。

尽管您是在重载方法的上下文中发现此问题的,但重载掩盖了实际问题。如果我们消除过载,将更容易理解该问题。

因此,为此,请考虑以下程序:

type
  TAnimal = class
  end;

  TDog = class(TAnimal)
  end;

procedure GetAnimal(var AAnimal: TAnimal);
begin
  AAnimal := TAnimal.Create;
end;

var
  Dog: TDog;

begin
  GetAnimal(Dog);
end.
Run Code Online (Sandbox Code Playgroud)

无法在GetAnimal对此错误的调用中进行编译:

[dcc32错误]:E2033实际和形式var参数的类型必须相同

为什么编译器拒绝此?好吧,想象一下它是否接受了这一点。如果这样做的话,则在GetAnimal返回Dog变量时,该变量将引用不是的对象TDog

要查看此内容,请将程序主体更改为如下所示:

GetAnimal(TAnimal(Dog));
Writeln(Dog.InheritsFrom(TDog));
Run Code Online (Sandbox Code Playgroud)

这样做时,程序会编译,但输出是

在您的程序上下文中,编译器面临一些重载。如本例所示,编译器无法接受将TDog变量传递给TAnimalvar参数,因此它拒绝该重载。它知道它不能将TDog变量传递给string参数,因此被拒绝。此时,不存在任何重载方法,因此会出现错误消息。