Delphi: Переопределенный потомок виртуального конструктора не вызывается из-за перегрузки - PullRequest
1 голос
/ 08 октября 2010

Еще один из моей серии вопросов, касающихся конструкторов в 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;

Где потомки 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) {...}

Это кажется проблемой, только если:

  • конструктор является виртуальным
  • вы перегружаете конструкторы

Является ли правило, что вы не можете иметь один конструктор перегружать другой?

1 Ответ

8 голосов
/ 08 октября 2010

Ошибка ..

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.

...