根据我的想法,下面的代码应该无法编译,因为方法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.
答案 0 :(得分:4)
TSubB.DoSomething
确实不可见。但编译器在DoSomething
的所有祖先类中查找。它找到的第一个是可见的TBase.DoSomething
。因此程序编译。
关于你的编辑,这会改变一切。编辑后,您有两个不同的TBase
类。 dpr文件中定义的那个,以及uBase
单元中定义的那个。那是你想要的。并且在dpr文件中定义基类确实没有意义,因为单元不能使用dpr文件。