Delphi: Как добавить другой конструктор к потомку? - PullRequest
7 голосов
/ 07 октября 2010

Обновление: Пример, который я первоначально имел, был довольно сложным.Вот простой пример из 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 жалуется, что мой новый конструктор скрывает старый конструктор.

Метод «Создать» скрывает виртуальный метод базового типа «TXMLStream»

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

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

Ответы [ 4 ]

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

Моя немедленная реакция - использовать ключевое слово 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
3 голосов
/ 07 октября 2010

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

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;
1 голос
/ 07 октября 2010

Также помните, что конструкторы НЕ ДОЛЖНЫ называться 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;

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

1 голос
/ 07 октября 2010

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

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;
...