Delphi:重写的虚拟构造函数后代未被重载调用
这是我关于 Delphi 构造函数的一系列问题中的另一个问题。
我有一个具有虚拟构造函数的基类:
TComputer = class(TObject)
public
constructor Create(Teapot: Integer); virtual;
end;
构造函数在有人需要调用时
var
computerClass: class of TComputer;
computer: TComputer;
begin
computer := computerClass.Create(nTeapot);
是虚拟的构造函数在后代中被重写
:
TCellPhone = class(TComputer)
public
constructor Create(Teapot: Integer); override;
end;
TiPhone = class(TCellPhone )
public
constructor Create(Teapot: Integer); override;
end;
其中TCellPhone
和TiPhone
后代每个都有机会进行自己的初始化(为了便于阅读而未包括成员)。
但现在我向某个祖先添加了一个重载的构造函数:
TCellPhone = class(TComputer)
public
constructor Create(Teapot: Integer); override; overload;
constructor Create(Teapot: Integer; Handle: string); overload;
end;
TCellPhone 中的备用构造函数调用另一个虚拟构造函数,因此它总是获得正确的重写行为:
constructor TCellPhone.Create(Teapot: Integer; Handle: string);
begin
TCellPhone.Create(Teapot); //call sibling virtual constructor
FHandle := Handle;
end;
问题是后代、重写的构造函数永远不会叫。实际的堆栈跟踪调用链是:
phone := TiPhone.Create(37, 'spout')
constructor TCellPhone.Create(Teapot: Integer; Handle: string)
constructor TCellPhone.Create(Teapot: Integer)
constructor TComputer.Create(Teapot: Integer)
TObject.Create
对 TCellPhone.Create(int)
的同级调用是虚拟的,应该调用 TiPhone
中的后代、重写方法:
phone := TiPhone.Create(37, 'spout')
constructor TCellPhone.Create(Teapot: Integer; Handle: string)
constructor TiPhone.Create(Teapot: Integer)
constructor TCellPhone.Create(Teapot: Integer)
constructor TComputer.Create(Teapot: Integer)
TObject.Create
因此,Delphi 尝试使用同级虚拟构造函数似乎无法按预期工作。
那么一个构造函数使用另一个构造函数是一个坏主意吗?设计意图是重载构造函数中的代码是彼此的复制粘贴版本吗?
我注意到在 .NET 中,一些构造函数相互链接:
public Bitmap(int width, int height) : this(width, height, PixelFormat.Format32bppArgb) {}
public Bitmap(int width, int height, PixelFormat format) {...}
这似乎只是一个问题,如果:
- 构造函数是虚拟的
- 您重载了构造函数
规则是不能让一个构造函数重载另一个构造函数吗?
Yet another in my series of questions regarding constructors in Delphi.
i have a base class that has has the virtual constructor:
TComputer = class(TObject)
public
constructor Create(Teapot: Integer); virtual;
end;
The constructor is virtual for the times that someone needs to call
var
computerClass: class of TComputer;
computer: TComputer;
begin
computer := computerClass.Create(nTeapot);
The constructor is overridden
in descendants:
TCellPhone = class(TComputer)
public
constructor Create(Teapot: Integer); override;
end;
TiPhone = class(TCellPhone )
public
constructor Create(Teapot: Integer); override;
end;
Where TCellPhone
and TiPhone
descendants each have their opportunity to do their own initialization (of members not included for readability).
But now i add an overloaded constructor to some ancestor:
TCellPhone = class(TComputer)
public
constructor Create(Teapot: Integer); override; overload;
constructor Create(Teapot: Integer; Handle: string); overload;
end;
The alternate constructor in TCellPhone calls the other virtual constructor, so it always gets the proper overridden behaviour:
constructor TCellPhone.Create(Teapot: Integer; Handle: string);
begin
TCellPhone.Create(Teapot); //call sibling virtual constructor
FHandle := Handle;
end;
The problem is that the descendant, overridden, constructor is never called. The actual stack trace chain of calls is:
phone := TiPhone.Create(37, 'spout')
constructor TCellPhone.Create(Teapot: Integer; Handle: string)
constructor TCellPhone.Create(Teapot: Integer)
constructor TComputer.Create(Teapot: Integer)
TObject.Create
The sibling call to TCellPhone.Create(int)
, which is virtual, should have called the descendant, overridden, method in TiPhone
:
phone := TiPhone.Create(37, 'spout')
constructor TCellPhone.Create(Teapot: Integer; Handle: string)
constructor TiPhone.Create(Teapot: Integer)
constructor TCellPhone.Create(Teapot: Integer)
constructor TComputer.Create(Teapot: Integer)
TObject.Create
So it seems that attempts to use a sibling virtual constructor is Delphi do not work as expected.
Is it then a bad idea for one constructor to use another? Is the design intention that code in overloaded constructors be copy-paste versions of each other?
i notice in .NET that some constructors chain to each other:
public Bitmap(int width, int height) : this(width, height, PixelFormat.Format32bppArgb) {}
public Bitmap(int width, int height, PixelFormat format) {...}
This only seems to be a problem if:
- a constructor is virtual
- you overload the constructors
Is the rule that you cannot have one constructor overload another?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
呃..
那应该是:
您只是创建了一个新的 TCellphone 实例,而不是调用其他 Create 方法。
Errr..
That should be:
You were just creating a new TCellphone instance and not calling the other Create method.