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;
теперь будут доступны оба конструктора.