Frage

ich suche auf verstehen

  • virtuelle
  • Überschreiben
  • Überlastung
  • reintroduce

, wenn auf Objektkonstruktoren angewendet. Jedes Mal, wenn ich zufällig Schlüsselwörter, bis der Compiler Shuts aufaddieren -. Und (nach 12 Jahren Entwicklung mit Delphi) ich würde vielmehr wissen, was ich tue, anstatt zu versuchen, die Dinge dem Zufall

eine hypothetische Menge von Objekten gegeben:

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

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

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); override;
    constructor Create(Cup: Integer; Teapot: string); override;
end;

Die Art, wie ich sie zu verhalten will, ist wohl offensichtlich aus den Erklärungen, aber:

  • TComputer hat den einfachen Konstruktor und Nachkommen kann sie außer Kraft setzen
  • TCellPhone hat einen alternativen Konstruktor und Nachkommen kann es außer Kraft setzen
  • TiPhone überschreibt die beiden Konstrukteure, die geerbte Version jedes
  • Aufruf

Nun wird dieser Code nicht kompilieren. Ich möchte verstehen, Warum es funktioniert nicht. Ich möchte auch die richtige Art und Weise verstehen, Konstrukteuren außer Kraft zu setzen. Oder vielleicht könnten Sie nie Konstrukteurs außer Kraft setzen? Oder vielleicht ist es durchaus akzeptabel, außer Kraft zu setzen Bauer? Vielleicht sollten Sie nie mehrere Konstrukteure haben, vielleicht ist es völlig akzeptabel ist, mehrere Konstrukteure zu haben.

Ich möchte die Warum verstehen. Fixing es wäre dann klar sein.

Siehe auch

Edit: ich suche auch einige Überlegungen in der Größenordnung von virtual zu bekommen, override, overload, reintroduce. Denn bei dem Versuch, alle Kombinationen von Keywords, die Anzahl der Kombinationen explodiert:

  • virtual; Überlastung;
  • virtual; außer Kraft setzen;
  • überschreiben; Überlastung;
  • überschreiben; virtuell;
  • virtual; außer Kraft setzen; Überlastung;
  • virtual; Überlast; außer Kraft setzen;
  • Überlastung; virtuelle; außer Kraft setzen;
  • überschreiben; virtuelle; Überlastung;
  • überschreiben; Überlast; virtuell;
  • Überlastung; außer Kraft setzen; virtuell;
  • etc

Edit 2: Ich denke, wir sollten beginnen mit " wird die Objekthierarchie sogar möglich gegeben ?" Wenn nicht, warum nicht? Zum Beispiel ist es grundsätzlich falsch einen Konstruktor von einem Vorfahren zu haben?

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

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

ich würde erwarten, dass TCellPhone jetzt zwei Konstrukteuren hat. Aber ich kann nicht die Kombination von Schlüsselwort in Delphi finden, um es denkt, das ist eine gültige Sache zu tun. grundlegend falsch Bin ich denke ich zwei Konstrukteure hier in TCellPhone haben kann?


  

Hinweis: Alles unterhalb dieser Linie ist nicht unbedingt die Antwort erforderlich   Frage - aber es hilft zu erklären,   mein Denken. Vielleicht können Sie sehen,   basierend auf meine Denkprozesse, was   fundemantale Ich vermisse, dass   alles klar macht.

Nun sind diese Erklärungen nicht kompilieren:

//Method Create hides virtual method of base type TComputer:
TCellPhone = class(TComputer)
   constructor Create(Cup: Integer; Teapot: string);  virtual;

//Method Create hides virtual method of base type TCellPhone:
TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); override;
   constructor Create(Cup: Integer; Teapot: string); overload;  <--------
end;

Also zuerst werde ich versuchen, TCellPhone fixieren. Ich werde beginnen, indem zufällig Hinzufügen des overload Schlüsselwort (ich weiß, ich will nicht reintroduce weil das den anderen Konstruktor verstecken würde, was ich will nicht):

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

Aber das fehlschlägt. Field definition not allowed after methods or properties

ich weiß aus Erfahrung, dass, obwohl ich nach einer Methode oder Eigenschaft nicht ein Feld habe, wenn ich die Reihenfolge der virtual und overload Schlüsselwort umkehren: Delphi wird zum Schweigen bringen:

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

Aber ich immer noch den Fehler:

  

Die Methode ‚Create‘ Häute virtuelle Methode des Basistypen ‚TCOMPuter "

Also ich versuche, beiden Schlüsselwörter zu entfernen:

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

Aber ich immer noch den Fehler:

  

Die Methode 'Create' Häute virtuelle Methode des Basistypen 'TComputer'

Also ich mich damit abfinden, jetzt versucht reintroduce:

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

Und jetzt TCellPhone compiliert, aber es hat alles viel schlimmer für TiPhone gemacht:

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); override; <-----cannot override a static method
   constructor Create(Cup: Integer; Teapot: string); override; <-----cannot override a static method
end;

Beide klagen darüber, dass ich sie nicht außer Kraft setzen kann, so dass ich das override Stichwort entfernen:

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

Aber jetzt ist die zweite schaffen, sagt es mit Überlastung markiert werden muß, was ich tue (in der Tat i sowohl als Überlast markieren würde, da ich weiß, was passieren wird, wenn ich nicht tun):

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

Alle alles ist gut in dem interface Abschnitt. Leider werden meine Ausführungen nicht. Mein einziger Parameter Konstruktor TiPhone kann den geerbten Konstruktor nicht aufrufen:

constructor TiPhone.Create(Cup: Integer);
begin
    inherited Create(Cup); <---- Not enough actual parameters
end;
War es hilfreich?

Lösung

Ich sehe zwei Gründe, um Ihre ursprünglichen Satz von Deklarationen kompilieren sollte nicht sauber:

  1. Es sollte eine Warnung sein in TCellPhone, dass sein Konstruktor versteckt die Methode der Basisklasse. Dies liegt daran, die Basis-Klasse Methode ist virtuelle , und die Compiler Sorgen, dass Sie ohne Überschreiben die Basisklasse Methode a neue Methode mit dem gleichen Namen sind einzuführen. Es spielt keine Rolle, dass die Unterschriften unterscheiden. Wenn Ihre Absicht ist in der Tat die Methode der Basisklasse zu verstecken, dann müssen Sie verwenden reintroduce auf der Nachkomme Erklärung, als eine Ihrer blinden Vermutungen zeigte. Der einzige Zweck dieser Richtlinie ist es, die Warnung zu unterdrücken; es hat keinen Einfluss auf das Laufzeitverhalten.

    Das Ignorieren, was mit TIPhone passieren wird später die folgende TCellPhone Erklärung ist das, was man sich wünschen kann. Es verbirgt sich die Vorfahren Methode, aber Sie wollen es auch virtuell sein. Es wird nicht die virtualness der Vorfahren Methode erbt, weil sie zwei völlig getrennte Verfahren, die nur die gleichen Namen haben passieren. Daher müssen Sie virtual auf die neue Erklärung auch nutzen.

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

    Der Basisklassenkonstruktor, TComputer.Create wird auch ein Verfahren zum Verstecken seine Vorfahren, TObject.Create, aber da das Verfahren in TObject nicht virtuell ist, wird der Compiler nicht darüber warnen. Ausblenden von nicht-virtuellen Methoden geschieht die ganze Zeit und ist in der Regel unauffällig.

  2. Sie sollten einen Fehler angezeigt in TIPhone, weil es nicht mehr jeden einargumentigen Konstruktor außer Kraft zu setzen. Sie versteckte es in TCellPhone. Da Sie zwei Konstrukteure haben wollen, reintroduce klar nicht die richtige Wahl früher zu verwenden. Sie wollen nicht den Basisklassenkonstruktor zu verbergen; Sie wollen, dass es mit einem anderen Konstruktor erweitern.

    Da Sie beide Konstrukteure wollen den gleichen Namen haben, müssen Sie die overload Richtlinie verwenden. Diese Richtlinie Bedürfnisse auf verwendet werden alle ursprünglichen Erklärungen - das erste Mal, jede einzelne Signatur eingeführt wird nachfolgenden Erklärungen in Nachkommen. Ich dachte, es war erforderlich, auf alle Erklärungen (auch die Basisklasse), und es tut nicht weh, das zu tun, aber ich denke, es ist nicht erforderlich. Also, Ihre Erklärungen sollten wie folgt aussehen:

    TComputer = class(TObject)
    public
      constructor Create(Cup: Integer);
        overload; // Allow descendants to add more constructors named Create.
        virtual;  // Allow descendants to re-implement this constructor.
    end;
    
    TCellPhone = class(TComputer)
    public
      constructor Create(Cup: Integer; Teapot: string);
        overload; // Add another method named Create.
        virtual;  // Allow descendants to re-implement this constructor.
    end;
    
    TiPhone = class(TCellPhone)
    public
      constructor Create(Cup: Integer);
        override; // Re-implement the ancestor's Create(Integer).
      constructor Create(Cup: Integer; Teapot: string);
        override; // Re-implement the ancestor's Create(Integer, string).
    end;
    

Moderne Dokumentation sagt, was um alles in gehen sollte:

  

reintroduce ; Überlast ; Bindung ; Aufrufkonvention ; abstrakt ; Warnung

     

Dabei steht Bindung ist virtuelle , dynamische oder Überschreibung ; Aufrufkonvention ist registrieren , pascal , cdecl , stdcall oder safecall ; und Warnung ist Plattform , deprecated oder Bibliothek .

Das sind sechs verschiedene Kategorien, aber in meiner Erfahrung ist es selten mehr als drei auf jeder Erklärung zu haben. (Zum Beispiel Funktionen, dass Bedarf Aufrufkonventionen angegeben sind wahrscheinlich diese Methoden nicht, so dass sie nicht virtuell sein können.) Ich habe nie den Auftrag erinnern; Ich habe es nie dokumentierte bis heute zu sehen. Stattdessen denke ich, es hilfreicher ist jede Richtlinie der Zweck merken . Wenn Sie merken, welche Richtlinien Sie benötigen für verschiedene Aufgaben, werden Sie am Ende mit nur zwei oder drei, und dann einen gültigen Auftrag zu erhalten, es ist ziemlich einfach zu experimentieren. Der Compiler kann mehrere Aufträge annehmen, aber keine Sorge - um bei der Bestimmung Bedeutung ist nicht wichtig. Jede Bestellung der Compiler akzeptiert die gleiche Bedeutung hat wie jeder andere haben (mit Ausnahme der Aufrufkonventionen, wenn Sie erwähnen,mehr als einer von denen nur die letzten zählt, so tut das nicht).

Also, dann müssen Sie nur noch den Zweck der jeweiligen Richtlinie erinnern und darüber nachdenken, welche diejenigen zusammen keinen Sinn machen. Zum Beispiel können Sie nicht reintroduce und override zugleich verwenden, weil sie entgegengesetzte Bedeutungen haben. Und Sie können nicht virtual und override zusammen verwenden, da das eine das andere bedeutet.

Wenn Sie viele Richtlinien haben stapeln, können Sie immer schneiden overload aus dem Bild heraus, während Sie den Rest der Richtlinien erarbeiten Sie benötigen. Geben Sie Ihre Methoden verschiedene Namen, herauszufinden, welche der andere Richtlinien sie selbst brauchen, und dann overload wieder hinzufügen, während Sie geben sie alle die gleichen Namen wieder.

Andere Tipps

Beachten Sie, dass ich nicht über 5 Delphi, so dass ich meine Antworten bin stützen aus der neuesten Version, Delphi XE. Ich glaube nicht, dass wirklich keinen Unterschied hier machen, aber wenn es funktioniert, haben Sie gewarnt. :)

Dies ist vor allem auf Basis von http://docwiki.embarcadero.com/RADStudio/en/Methods , die die aktuelle Dokumentation, wie Methoden der Arbeit ist. Ihre Delphi 5-Hilfedatei hat wahrscheinlich etwas ähnliches wie dies auch.

Zunächst einmal, ein virtueller Konstruktor kann nicht viel Sinn hier machen. Es gibt ein paar Fälle, in denen Sie dies wünschen, aber das ist wahrscheinlich nicht ein. Schauen Sie sich auf http://docwiki.embarcadero.com/RADStudio/en/Class_References für eine situtation, wo Sie einen virtuellen Konstruktor brauchen - wenn Sie immer die Art Ihrer Objekte wissen bei der Codierung jedoch nicht wahr

.

Das Problem, das Sie dann in dem 1-Parameter-Konstruktor erhalten ist, dass Ihre Eltern-Klasse kein 1-Parameter-Konstruktor hat sich - geerbt Konstrukteuren nicht ausgesetzt sind. Sie können nicht inherited verwenden, um mehrere Ebene in der Hierarchie nach oben, können Sie nur Ihre unmittelbar Eltern anrufen. Sie müssen den 2-Parameter-Konstruktor mit einigem Standardwert nennen, oder einen 1-Parameter-Konstruktor TCellPhone auch hinzufügen.

In der Regel haben die vier Schlüsselwörter folgende Bedeutung:

  • virtual - Markieren Sie diese als eine Funktion, wo Sie wollen Laufzeit Dispatching (polymorphes Verhalten erlaubt). Dies ist nur für die erste Definition, nicht, wenn sie in Unterklassen überschrieben.
  • override -. Eine neue Implementierung für eine virtuelle Methode Geben Sie
  • overload -. Markieren Sie eine Funktion mit dem gleichen Namen wie eine andere Funktion, sondern eine andere Parameterliste
  • reintroduce -. Sagen Sie der Compiler Sie eigentlich bestimmt eine virtuelle Methode zu verstecken, anstatt nur zu Versorgungs override vergessen

Die Bestellung erforderlich ist, in der Dokumentation beschrieben:

  

können Methodendeklarationen enthalten   spezielle Richtlinien, die nicht verwendet werden   mit anderen Funktionen oder Prozeduren.   Richtlinien sollten in der Klasse erscheinen   nur Erklärung, nicht in der Definition   Erklärung und sollte immer sein,   aufgeführt in der folgenden Reihenfolge:

     

reintroduce; Überlast; Bindung;   Aufrufkonvention; abstrakt; Warnung

     

, wo die Bindung ist virtuell, dynamisch oder   außer Kraft setzen; Aufrufkonvention ist   Register, pascal, cdecl, stdcall oder   safecall; und Warnung Plattform,   Veraltete oder Bibliothek.

Dies ist eine funktionierende Implementierung der Definitionen gesucht:

program OnConstructors;

{$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;

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); overload; override;
    constructor Create(Cup: Integer; Teapot: string); override;
end;

{ TComputer }

constructor TComputer.Create(Cup: Integer);
begin
  Writeln('Computer: cup = ', Cup);
end;

{ TCellPhone }

constructor TCellPhone.Create(Cup: Integer; Teapot: string);
begin
  inherited Create(Cup);
  Writeln('Cellphone: teapot = ', Teapot);
end;

{ TiPhone }

constructor TiPhone.Create(Cup: Integer);
begin
  inherited Create(Cup);
  Writeln('iPhone: cup = ', Cup);
end;

constructor TiPhone.Create(Cup: Integer; Teapot: string);
begin
  inherited;
  Writeln('iPhone: teapot = ', Teapot);
end;

var
  C: TComputer;

begin

  C := TComputer.Create(1);
  Writeln; FreeAndNil(C);

  C := TCellPhone.Create(2);
  Writeln; FreeAndNil(C);
  C := TCellPhone.Create(3, 'kettle');
  Writeln; FreeAndNil(C);

  C := TiPhone.Create(4);
  Writeln; FreeAndNil(C);
  C := TiPhone.Create(5, 'iPot');

  Readln; FreeAndNil(C);

  end.

mit den Ergebnissen:

Computer: cup = 1

Computer: cup = 2

Computer: cup = 3
Cellphone: teapot = kettle

Computer: cup = 4
iPhone: cup = 4

Computer: cup = 5
Cellphone: teapot = iPot
iPhone: teapot = iPot

Der erste Teil ist in Übereinstimmung mit

Verwendung Überlastung beide, es ist die Art, wie ich es tun, und es funktioniert.

constructor Create; Overload; <- Nutzung überlastete hier

constructor Values; Overload; <- und hier

erinnere mich nicht den gleichen Namen für zwei unterschiedlichen Herstellern zu verwenden,

scroll top