【发布时间】:2011-04-22 00:30:12
【问题描述】:
我希望了解
- 虚拟
- 覆盖
- 过载
- 重新介绍
应用于对象构造函数时。每次我随机添加关键字直到编译器关闭 - 并且(在使用 Delphi 开发 12 年后)我宁愿知道我在做什么,而不是随机尝试。
给定一组假设的对象:
TComputer = class(TObject)
public
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual;
end;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
constructor Create(Cup: Integer; Teapot: string); override;
end;
我希望他们的行为方式从声明中可能很明显,但是:
-
TComputer有简单的构造函数,后代可以覆盖它 -
TCellPhone有一个备用构造函数,后代可以覆盖它 -
TiPhone覆盖两个构造函数,调用每个构造函数的继承版本
现在该代码无法编译。我想了解为什么它不起作用。我也想了解重写构造函数的正确方法。或者也许你永远无法覆盖构造函数?或者也许重写构造函数是完全可以接受的?也许你永远不应该有多个构造函数,也许拥有多个构造函数是完全可以接受的。
我想了解为什么。修复它就很明显了。
另见
- Delphi: How to hide ancestor constructors?
- Reintroducing functions in Delphi
- Delphi: How to add a different constructor to a descendant?
编辑:我也希望按virtual、override、overload、reintroduce 的顺序进行推理。因为在尝试所有关键字组合时,组合的数量会爆炸式增长:
- 虚拟;过载;
- 虚拟;覆盖;
- 覆盖;过载;
- 覆盖;虚拟的;
- 虚拟;覆盖;过载;
- 虚拟;超载;覆盖;
- 过载;虚拟的;覆盖;
- 覆盖;虚拟的;过载;
- 覆盖;超载;虚拟的;
- 过载;覆盖;虚拟的;
- 等
编辑 2: 我想我们应该从“给定的对象层次结构是否可能?”开始,如果没有,为什么不呢?例如,使用祖先的构造函数是根本不正确的吗?
TComputer = class(TObject)
public
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual;
end;
我希望TCellPhone 现在有两个构造函数。但我无法在 Delphi 中找到关键字组合,使其认为这是一件有效的事情。我认为我可以在TCellPhone 中有两个构造函数,我是否从根本上错了?
注意:此行以下的所有内容并非严格要求回答 问题 - 但它确实有助于解释 我的想法。也许你可以看到, 根据我的思维过程,什么 我缺少的基本部分 让一切都清楚。
现在这些声明无法编译:
//Method Create hides virtual method of base type TComputer:
TCellPhone = class(TComputer)
constructor Create(Cup: Integer; Teapot: string); virtual;
//Method Create hides virtual method of base type TCellPhone:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
constructor Create(Cup: Integer; Teapot: string); overload; <--------
end;
所以首先我会尝试修复TCellPhone。我将从随机添加 overload 关键字开始(我知道我不想要 reintroduce 因为那会隐藏另一个我不想要的构造函数):
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual; overload;
end;
但这失败了:Field definition not allowed after methods or properties。
我从经验中知道,即使我在方法或属性之后没有字段,如果我颠倒 virtual 和 overload 关键字的顺序:Delphi 会闭嘴:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
但我仍然得到错误:
方法 'Create' 隐藏基本类型 'TComputer' 的虚拟方法
所以我尝试删除这两个关键字:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string);
end;
但我仍然得到错误:
方法 'Create' 隐藏基本类型 'TComputer' 的虚拟方法
所以我辞职现在尝试reintroduce:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); reintroduce;
end;
现在 TCellPhone 可以编译,但它让 TiPhone 的情况变得更糟:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override; <-----cannot override a static method
constructor Create(Cup: Integer; Teapot: string); override; <-----cannot override a static method
end;
两者都抱怨我无法覆盖它们,所以我删除了 override 关键字:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer);
constructor Create(Cup: Integer; Teapot: string);
end;
但现在第二次创建说它必须标记为重载,我这样做了(实际上我会将两者都标记为重载,因为我知道如果我不这样做会发生什么):
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); overload;
constructor Create(Cup: Integer; Teapot: string); overload;
end;
interface 部分中的一切都很好。不幸的是,我的实现不起作用。我的TiPhone单参数构造函数不能调用继承的构造函数:
constructor TiPhone.Create(Cup: Integer);
begin
inherited Create(Cup); <---- Not enough actual parameters
end;
【问题讨论】:
-
来自 Delphi 9 帮助:方法声明可以包含不与其他函数或过程一起使用的特殊指令。指令应仅出现在类声明中,而不应出现在定义声明中,并且应始终按以下顺序列出:
reintroduce;overload; 绑定; 调用约定;abstract; 警告,其中绑定为virtual、dynamic或override;调用约定为register、pascal、cdecl、stdcall或safecall;警告是platform、deprecated或library。 -
Delphi 5 仍然带有出色的印刷语言指南,详细解释了这些声明。
-
试试 TCellPhone.Create(Cup);而不是继承的 Create(Cup);
标签: delphi constructor delphi-5 constructor-chaining