一个构造函数调用另一个重载构造函数是否有意义?

3
如果我有两个重载的构造函数,一个带参数,一个不带参数:
constructor Create; overload;
constructor Create(Param: TObject); overload;

如果我想要第一个代码运行,调用它在第二个里面是有意义的吗?并且继承时也需要先调用父类构造函数吗?
constructor TMyType.Create(Param: TObject);
begin
  inherited Create;
  Create;
  FParam := Param;
end;

谢谢!


1
我们怎么可能知道这是否有意义?我们无法看到所有的代码。也许你有一些很好的理由这样做。话虽如此,我想不出任何好的理由,所以我预测这段代码是虚假的。 - David Heffernan
是的,调用一个较为简单的构造函数来调用另一个更复杂的构造函数是一种常见做法。 然而,并不像你所描述的那么简单:需要避免重复继承的调用。 - Adrian Maire
2个回答

0
如果我想要第一个代码运行,是否有意义在第二个里面调用它并且继承也首先调用父级构造函数?
不。因为你的第一个构造函数应该自己调用继承的那个,因此最终继承的构造函数将被调用两次,这可能是不期望的。
否则,如果您的无参不调用继承的那个,则它几乎不是一个合适的构造函数,应该被删除。
因此正确的方法应该是这样的:
constructor TMyType.Create(Param: TObject); overload;
begin
  Create();
  FParam := Param;
end;

constructor TMyType.Create();  overload;
begin
  inherited Create(); // for both constructors

  ...some common code
end;

然而,在Delphi中还有另一种可能性。
constructor Create; overload;
constructor Create(Param: TObject); overload;
procedure AfterConstruction; override;


constructor TMyType.Create(Param: TObject); 
begin
  inherited Create(); 

  FParam := Param;
end;

constructor TMyType.Create();
begin
  inherited ; 

 ... maybe some extra code
end;

procedure TMyType.AfterConstruction();
begin
    inherited;

  ...some common code
end;

请注意,"common code" 何时执行以及何时执行 "FParam := Param;"。
在第一种方式中,流程如下:
- 创建(Param) - ..Create() - ....Inherited Create() - ....公共代码 - ..FParam := Param; - AfterConstruction(空)
在第二个序列中,顺序会有所不同
- 创建(Param)或创建() - ..Inherited Create() - ..FParam := Param; - AfterConstruction - ..公共代码
正如您所看到的,这些块被执行的顺序被颠倒了。
也许你根本不需要多个构造函数?
constructor TMyType.Create(const Param: TObject = nil); 
begin
  inherited; 

 ... Some code

  FParam := Param;
end;

2
在构造函数中使用隐式的 AfterConstruction 会让人感到困惑。最好将公共部分放在一个方法中,并从两个构造函数中调用该方法。 - LU RD
然后你有10个具有非平凡依赖图的构造函数,但这仍然很容易。然而,在2年内,另一个人制作了您的类的重孙后代,突然事情变得混乱。YMMV,但我认为AfterConstruction是一个非常酷的功能。 - Arioch 'The
这个回答太长了,对于一个简单的“不要这样做”来说。如果两个构造函数中都有要执行的代码,则应将该特定代码放在一个专用方法中,以便从两个构造函数中调用。 - Peter
1
我的理解是AfterConstruction的目的是调用在构造函数中无法运行的代码。这是为了克服Delphi和C++Builder之间的差异而引入的,因为虚方法处理方式不同(在组件中使用TCustomForm等)。 - LU RD
@petervonča,就这样吧,Delphi不允许将构造函数作为方法调用。 - Arioch 'The
显示剩余8条评论

-3

是的,你的代码非常合理,构造函数的调用正好符合预期。

Delphi对象模型支持既调用继承构造函数又不调用继承构造函数的构造函数。

如果你不确定,请尝试以下操作:

program Project5;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TMyBase = class
    constructor Create;
  end;

  TMyType = class(TMyBase)
    constructor Create; overload;
    constructor Create(Param: TObject); overload;
  end;

constructor TMyBase.Create;
begin
  Writeln('TMyBase.Create');
end;

constructor TMyType.Create;
begin
  Writeln('TMyType.Create');
end;

constructor TMyType.Create(Param: TObject);
begin
  inherited Create;
  Create;
  Writeln('TMyType.Create(Param)');
end;

begin
  TMyType.Create(TObject.Create);
  Readln;
end.

1
一个没有调用inherited的构造函数不是一个合适的构造函数。两个构造函数都需要调用inherited。如果一个构造函数需要调用另一个构造函数,则不要在第一个构造函数中调用inherited,让第二个构造函数调用它。Arioch'The所描述的方式是正确的方式。 - Remy Lebeau
1
@RemyLebeau - 对于 Delphi 来说,一个没有调用 inherited 的构造函数和一个调用了它的构造函数一样好。我们在这里讨论的是 Delphi,而不是一个想象中的完美编程语言。 - kludg
你可以遵循常识和传统的继承思想(使用继承构造函数),或者你可以为“有意义”的概念提供自己的非标准定义。 - Arioch 'The
@Serg 跳过基类构造函数并不是很有意义。这样做时,您期望对象处于什么状态?是的,您可以这样做,但通常情况下不应该这样做。 - David Heffernan
@Arioch'The:在派生构造函数中直接初始化祖先成员不是一个好的实践,这应该由基类构造函数来完成。 - Remy Lebeau
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接