Delphi: Wie einen anderen Konstruktor ein Nachkomme hinzufügen?
-
28-09-2019 - |
Frage
Update: Das Beispiel war ich ursprünglich hatte Art komplexer. Hier ist ein einfache 8-Zeilen-Beispiel, das alles in einem Codeblock erklärt. Der folgende nicht Compile gibt eine Warnung aus:
TComputer = class(TObject)
public
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual;
end;
Hinweis: Diese Frage ist Teil 3 in meiner laufenden Reihe von Fragen über die subtlties von Konstrukteuren in Delphi
Original Frage
Wie kann ich einen Konstruktor zu einer vorhandenen Klasse hinzufügen?
Lassen Sie uns geben, ein hypothetisches Beispiel (das heißt eine, die ich hier oben im SO-Editor tippen bin so kann es oder nicht kompilieren):
TXHTMLStream = class(TXMLStream)
public
...
end;
Ferner wird angenommen, dass die normale Verwendung von TXHTMLStream
viel wiederholtem Code beteiligt Durchführung, bevor sie verwendet werden kann:
var
xs: TXHTMLStream;
begin
xs := TXHTMLStream.Create(filename);
xs.Encoding := UTF32;
xs.XmlVersion := 1.1;
xs.DocType := 'strict';
xs.PreserveWhitespace := 'true';
...
xs.Save(xhtmlDocument);
Nehmen wir an, ich einen Konstruktor erstellen möchten, die alle, dass Text Setup-Code vereinfacht:
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;
Das vereinfacht die Nutzung des Objekts:
var
xs: TXHTMLStream;
begin
xs := TXHTMLStream.Create(filename, UTF32);
xs.Save(xhtmlDocument);
Außer jetzt Delphi beklagt, dass mein neuer Konstruktor versteckt die alte Konstruktor.
Die Methode 'Create' Häute virtuelle Methode des Basistypen 'TXMLStream'
ich habe sicher nicht mittlere verstecken die Vorfahren schaffen -. I wollen beide
Wie füge ich einen Konstruktor (mit andere Signatur) zu einer abgeleiteten Klasse, während der Vorfahren Konstruktor zu halten, so dass es nach wie vor verwendet werden kann?
Lösung
Meine unmittelbare Reaktion ist das overload
Schlüsselwort zu verwenden, wie in:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;
Bearbeiten : Danke Ian für die Bearbeitung, die eine Antwort aus meiner Antwort macht. Ich würde gerne glauben, dass ich es bekam für Tapferkeit, so dass ich ein vollständigeres Beispiel dazu beitragen werde:
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.
mit dem Ergebnis,:
constructed computer: cup = 1
constructed computer: cup = 2
constructed computer: cup = 3
constructed cellphone: Teapot = kettle
Andere Tipps
Sie können zwei neue ladenen Konstruktoren erstellen, zum Beispiel:
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;
Ein andere Möglichkeit ist es, einen neuen Konstruktor mit Standard-Parameterwerten zu schreiben, wo der Teil der Signatur mit Nicht-Standard-Parametern entspricht den ursprünglichen Konstruktor in der Basisklasse:
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;
Denken Sie auch daran, dass Konstrukteure haben nicht erstellen aufgerufen werden. Ältere Versionen von Delphi nicht Methodenüberladung, so dass Sie verschiedene Namen verwenden haben:
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;
Die beiden Konstrukteure werden nun zur Verfügung.