【发布时间】:2014-05-13 10:55:17
【问题描述】:
在我看来,下面的代码应该无法编译,因为方法 TSubB.DoSomething 是受保护的,因此在 TSubA.DoSomething 中是不可见的。 (他们是兄弟姐妹,而不是父/子。)事实上它编译并且当你运行它时,它实际上调用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.
【问题讨论】:
-
关于
private、protected的可见性以及与strict的结合参见stackoverflow.com/questions/16554781/…