【问题标题】:Delphi: Overridden virtual constructor descendant not being called by overloadDelphi:重写的虚拟构造函数后代未被重载调用
【发布时间】:2010-10-08 15:56:22
【问题描述】:

我关于 Delphi 构造函数的一系列问题中的另一个问题。

我有一个具有虚拟构造函数的基类:

TComputer = class(TObject)
public
    constructor Create(Teapot: Integer); virtual;
end;

构造函数在有人需要调用的时候是虚拟的

var
   computerClass: class of TComputer;
   computer: TComputer;
begin     
   computer := computerClass.Create(nTeapot);

构造函数在后代中是overridden

TCellPhone = class(TComputer) 
public
   constructor Create(Teapot: Integer); override;
end;

TiPhone = class(TCellPhone ) 
public
   constructor Create(Teapot: Integer); override;
end;

TCellPhoneTiPhone 的后代每个都有机会进行自己的初始化(为了便于阅读,不包括成员)。

但是现在我向某个祖先添加了一个重载的构造函数:

TCellPhone = class(TComputer) 
public
   constructor Create(Teapot: Integer); override; overload;
   constructor Create(Teapot: Integer; Handle: string); overload;
end;

TCellPhone 中的备用构造函数调用另一个 virtual 构造函数,因此它始终获得正确的覆盖行为:

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) {...}

这似乎只是一个问题,如果:

  • 构造函数是虚拟的
  • 你重载了构造函数

你不能让一个构造函数重载另一个的规则吗?

【问题讨论】:

    标签: delphi constructor delphi-5 constructor-chaining


    【解决方案1】:

    错误..

    constructor TCellPhone.Create(Teapot: Integer; Handle: string);
    begin
       TCellPhone.Create(Teapot); //call sibling virtual constructor
    
       FHandle := Handle;
    end;
    

    应该是:

    constructor TCellPhone.Create(Teapot: Integer; Handle: string);
    begin
       Create(Teapot); //call sibling virtual constructor
    
       FHandle := Handle;
    end;
    

    您只是创建了一个新的 TCellphone 实例,而不是调用另一个 Create 方法。

    【讨论】:

    • +1。我正要回答这个问题,但你抢先了。
    • 谢谢。我只是认为inherited Create 调用了祖先——我必须 必须有一些东西来表明。 :\
    • 表示的东西是Self,@Ian:Self.Create(Teapot)。像往常一样,Self 是隐含的;您无需明确提及,正如 The_Fox 在这里演示的那样。
    • @Ian,如果要执行父级的构造函数,请调用inherited Create(Teapot)
    • @Rob Kennedy:我会使用Self,但Self 通常指的是一个对象。说“object”在构造函数期间存在是一个非常灰色的区域; Self 可能无效。我还想包含一些东西(anything),这样以后来的人(例如我)就不会说,“哦,嘿,他错过了这里的inherited”)。
    猜你喜欢
    • 2011-07-16
    • 1970-01-01
    • 2011-03-30
    • 2016-04-09
    • 2021-09-19
    • 2010-10-02
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    相关资源
    最近更新 更多