gpt4 book ai didi

delphi - 编译器允许调用同级类中的 protected 方法,但调用基类

转载 作者:行者123 更新时间:2023-12-03 15:52:14 25 4
gpt4 key购买 nike

根据我的想法,下面的代码应该无法编译,因为方法 TSubB.DoSomething 受到保护,因此从 TSubA.DoSomething 中不可见。 (它们是 sibling ,而不是父/子。)事实上,它会编译,并且当您运行它时,它实际上会调用 TBase.DoSomething。 (我对此很恼火,因为我忘记了 DoSomething 受到了保护。)

现在事情变得很奇怪了。如果我将 uBase.pas 中的代码粘贴到 Project1.dpr 中并从项目中删除 uBase.pas,我确实会收到编译器错误在那条线上。

谁能解释一下这是怎么回事?

(抱歉粘贴了这么多代码。这似乎确实是最小的测试用例。)

Project1.dpr

program Project1;
{$APPTYPE CONSOLE}

uses
uBase in 'uBase.pas',
uSubB in 'uSubB.pas';

var
obj : TBase;
begin
obj := TSubA.Create;
Writeln(obj.Something);
obj.Free;
end.

uBase.pas

unit uBase;
interface
type
TBase = class (TObject)
protected
class function DoSomething : string; virtual;
public
function Something : string;
end;

TSubA = class (TBase)
protected
class function DoSomething : string; override;
end;

implementation
uses
uSubB;

function TBase.Something : string;
begin
Result := DoSomething;
end;

class function TBase.DoSomething : string;
begin
Result := 'TBase'; // Override in subclass.
end;

class function TSubA.DoSomething : string;
begin
Result := 'Same as ' + TSubB.DoSomething; // Expect compiler error here
end;
end.

uSubB.pas

unit uSubB;

interface

uses
uBase;

type
TSubB = class (TBase)
protected
class function DoSomething : string; override;
end;

implementation

class function TSubB.DoSomething : string;
begin
Result := 'TSubB';
end;

end.
<小时/>

编辑

如果将所有代码从 uBase.pas 移至 Project1.dpr 并从项目中删除 uBase.pas,则编译器将不再接受对 TSubB.DoSomething 的调用。我不确定为什么这在编译器的可见性方面有什么不同。

修订后的 Project1.dpr

program Project1;
{$APPTYPE CONSOLE}

uses
// uBase in 'uBase.pas',
uSubB in 'uSubB.pas';

type
TBase = class (TObject)
protected
class function DoSomething : string; virtual;
public
function Something : string;
end;

TSubA = class (TBase)
protected
class function DoSomething : string; override;
end;

function TBase.Something : string;
begin
Result := DoSomething;
end;

class function TBase.DoSomething : string;
begin
Result := 'TBase'; // Override in subclass.
end;

class function TSubA.DoSomething : string;
begin
Result := 'Same as ' + TSubB.DoSomething; // Actual compiler error
end;

var
obj : TBase;
begin
obj := TSubA.Create;
Writeln(obj.Something);
obj.Free;
end.

最佳答案

TSubB.DoSomething 确实不可见。但编译器会在所有祖先类中查找 DoSomething。它找到的第一个是可见的TBase.DoSomething。因此程序可以编译。

至于你的编辑,这改变了一切。编辑后,您将拥有两个不同的 TBase 类。一个在 dpr 文件中定义,一个在 uBase 单元中定义。这就是你的意图。在 dpr 文件中定义基类确实没有意义,因为单元不能使用 dpr 文件。

关于delphi - 编译器允许调用同级类中的 protected 方法,但调用基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23629288/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com