Delphi: как добавить другой конструктор к потомку?

обновление: пример, который у меня изначально был, был довольно сложным. Вот простой пример 8 строк, который объясняет все в одном блоке кода. Следующее не компилируется предупреждает:

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

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer; Teapot: string); virtual;
end;

Примечание: этот вопрос является частью 3 в моей текущей серии вопросов о тонкостях конструкторов в Delphi

исходный вопрос

как добавить конструктор в существующий класс?

давайте приведем гипотетический пример (т. е. тот, который я печатаю здесь в Редакторе SO, чтобы он мог или не мог компилироваться):

TXHTMLStream = class(TXMLStream)
public
   ...
end;

далее предположим, что нормальное использование TXHTMLStream задействовано выполнение большого количества повторяющегося кода, прежде чем его можно будет использовать:

var
   xs: TXHTMLStream;
begin
   xs := TXHTMLStream.Create(filename);
   xs.Encoding := UTF32;
   xs.XmlVersion := 1.1;
   xs.DocType := 'strict';
   xs.PreserveWhitespace := 'true';
   ...

   xs.Save(xhtmlDocument);

предположим, что я хочу создать конструктор, который упрощает весь этот шаблонный код установки:

TXHTMLStream = class(TXMLStream)
public
    constructor Create(filename: string; Encoding: TEncoding); virtual;
end;

constructor TXHTMLStream.Create(filename: string; Encoding: TEncoding);
begin
   inherited Create(filename);
   xs.Encoding := Encoding;
   xs.XmlVersion := 1.1;
   xs.DocType := 'strict';
   xs.PreserveWhitespace := True;
   ...
end;

что упрощает использование объекта кому:

var
   xs: TXHTMLStream;
begin
   xs := TXHTMLStream.Create(filename, UTF32);
   xs.Save(xhtmlDocument);

кроме теперь Delphi жалуется, что мой новый конструктор скрывает старый конструктор.

метод "Create" скрывает виртуальный метод базового типа "TXMLStream"

Я, конечно, не mean чтобы скрыть предка создать - я хочу оба.

как добавить конструктор (с разные signature) для класса потомков, сохраняя при этом конструктор ancestor, чтобы его можно было использовать?

4 ответов


моя немедленная реакция-использовать overload ключевое слово, например:

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;

редактировать: спасибо Яну за редактирование, которое делает ответ из моего ответа. Я хотел бы думать, что я получил его за храбрость, поэтому я собираюсь внести более полный пример:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type

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

TCellPhone = class(TComputer)
public
    constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;

{ TComputer }

constructor TComputer.Create(Cup: Integer);
begin
  writeln('constructed computer: cup = ', Cup);
end;

{ TCellPhone }

constructor TCellPhone.Create(Cup: Integer; Teapot: string);
begin
  inherited Create(Cup);
  writeln('constructed cellphone: Teapot = ', Teapot);
end;

var
  C1, C2, C3: TComputer;

begin
  C1 := TComputer.Create(1);
  Writeln;
  C2 := TCellPhone.Create(2);
  Writeln;
  C3 := TCellPhone.Create(3, 'kettle');
  Readln;
end.

в результате:

constructed computer: cup = 1

constructed computer: cup = 2

constructed computer: cup = 3
constructed cellphone: Teapot = kettle

вы можете создать два новых перегруженных конструкторов, например:

type
  TXmlStream = class
  private
    FFileName: string;
  public
    constructor Create(const AFileName: string); virtual;
  end;

  TXhtmlStream = class(TXmlStream)
  private
    FEncoding: TEncoding;
  public
    constructor Create(const AFileName: string); overload; override;
    constructor Create(const AFileName: string; AEncoding: TEncoding); overload; virtual;
  end;

constructor TXmlStream.Create(const AFileName: string);
begin
  inherited Create;
  FFileName := AFileName;
end;

constructor TXhtmlStream.Create(const AFileName: string);
begin
  inherited Create(AFileName);
end;

constructor TXhtmlStream.Create(const AFileName: string; AEncoding: TEncoding);
begin
  inherited Create(AFileName);
  FEncoding := AEncoding;
end;

другая возможность-написать новый конструктор со значениями параметров по умолчанию, где часть подписи с параметрами не по умолчанию соответствует исходному конструктору в базовом классе:

type
  TXmlStream = class
  private
    FFileName: string;
  public
    constructor Create(const AFileName: string); virtual;
  end;

  TXhtmlStream = class(TXmlStream)
  private
    FEncoding: TEncoding;
  public
    constructor Create(const AFileName: string; AEncoding: TEncoding = encDefault); reintroduce; virtual;
  end;

constructor TXmlStream.Create(const AFileName: string);
begin
  inherited Create;
  FFileName := AFileName;
end;

constructor TXhtmlStream.Create(const AFileName: string; AEncoding: TEncoding);
begin
  inherited Create(AFileName);
  FEncoding := AEncoding;
end;

также помните, что конструкторы не должны называться Create. В старых версиях Delphi не было перегрузки метода, поэтому вам приходилось использовать разные имена:

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

TCellPhone = class(TComputer) 
private
  FTeapot: string;
public 
    constructor CreateWithTeapot(Cup: Integer; Teapot: string); virtual; 
end; 

...

constructor TCellPhone.CreateWithTeapot(Cup: Integer; Teapot: string); 
begin
  Create(Cup);
  FTeapot := Teapot;
end;

теперь будут доступны оба конструктора.