![]() |
virtual / override ??
Hi,
die Problemstellung ist folgende : ich brauche in abgeleiteten Forms eine Prozedur. Es steht aber beim Vorfahr noch nicht genau fest, was die im Endeffekt machen soll. Ich habe diese Prozedur nun im Vorfahr deklariert. Und zwar als "virtual". Die Nachkommen sind als "override" deklariert. Die 1. Frage ist nun, ob das so überhaupt richtig ist. Die nächste ist dann, warum Delphi die Ursprungsprozedur rausschmeißt, sofern sie "leer" ist. Die abgeleitete Prozedur erzeugt dann nämlich einen Compiler-Fehler (Identifier blabla...). Die Prozedur muß nämlich zunächst leer sein, da sie erst von den abgeleiteten Forms bestückt wird. Sie dient also quasi vorerst nur als Platzhalter. So ähnlich halt wie die Custom-Geschichten in der Delphi VCL. |
Re: virtual / override ??
definiere sie als (das was sie ist) abstract
Delphi-Quellcode:
Dann brauchst Du auch keine 'Dummy-Implementation' schreiben.
procedure Foo; virtual; abstract;
|
Re: virtual / override ??
Zitat:
Zitat:
edit: abstract kannt ich noch gar nicht ma anschauen^^ |
Re: virtual / override ??
[OT]Echt hammerhart. :shock: Da schreibt man mal so eine nicht ganz einfache Frage, in der Erwartung, daß wenn überhaupt, irgendwann nächste Woche eine Reaktion kommt und dann kommen sogar zwei. 8) [ENDE OT]
1. Das "abstract" ist mir unbekannt, wozu ist das da ? Muß mich wohl oder übel mit diesen Dingern intensiver beshäftigen. Wo steht nun mehr, als in den Delphi Handbüchern ? Dann noch die Kombinationen (und es gibt ja noch mehr: "reintroduce" usw.) Mir ist schon klar, daß das alles selten gebraucht wird, aber ich komme mit meinem umfangreichen Projekt nicht drumrum den kompletten Delphi-Sprachumfang zu kennen, egal ob DBs, Komponentenentwicklung, Zeiger usw. 2. Pseudo: wieso überschreibe ich was ? Es geht um die Ursprungsklasse. Wenn eine abgeleitete existiert, so kann die Ursprungsprozedur nicht einfach gelöscht werden. 8) Es sei denn sie wird nicht benutzt. Die Ursprungsprozedur wird nicht gelöscht, sofern nur ein Kommentar drin steht. Falls nicht, so ist sie weg und die abgeleitete Prozedur erzeugt einen Fehler, eben weil die Ursprungs-Prozedur eben fehlt. Nun steht aber in der abgeleiteten eine ShowMessage drin, sie dürfte insofern nicht gelöscht werden. |
Re: virtual / override ??
auf jeden fall abstract. und damit natürlich auch virtual ;). dann in den abgeleiteten klassen mit override überschreiben. auf überschriebene methoden kann man mit inherited zugreifen. bei konstruktoren sollte man das auch tunlichst zu allererst machen, bei konstruktoren analog zu allerletzt.
|
Re: virtual / override ??
abstract macht genau das was du suchst. es steht nur im interface und meldet delphi, dass da was sein muss. eine implementation braucht man nicht. allerdings kann man die klasse nicht erzeugen, solange noch ein "abstract" darin ist. man muss erst davon ableiten und das abstract mit einem override "füllen". das abstract ist sowas wie eine forward-deklaration, die aber erst bei den erben implementiert werden muss. das abstract automatisch auch virtual sein muss, ist klar.
...das war eine von den "basiswissen"-sachen, die wir im zweiten jahr delphi gelernt haben in der schule (wo wir sonst echt nicht viel machen) |
Re: virtual / override ??
NicoDe's Version in Ausführlich:
Abstrakt bedeutet dem Compiler, dass dies nur ein "Platzhalter" für eine Methode ist, die in einem Nachfahre des aktuellen Objektes (mit "override") implementiert wird und er nicht schon in diesem Objekt nach einer Implementation zu suchen braucht. Implementiert ein Nachfahre diese Methode dann doch nicht, gibt der Compiler eine Warnung: "Achtung: Objekt BlaFasel wird mit abstrakten Methoden instantiiert" aus um so anzuzeigen, dass wir da wohl was vergessen haben. Prinzip-Beispiel:
Delphi-Quellcode:
Gruß
TAnzeige = class TWinControl
public procedure Beschriften(Value:String); virtual; abstract; end; TLabelAnzeige = class(TAnzeige) private FLabel : TLabel public constructor Create(AOwner:TControl); override; destructor Destroy; override; procedure Beschriften(Value:String); override; end; TEditAnzeige = class(TAnzeige) private FEdit : TEdit public constructor Create(AOwner:TControl); override; destructor Destroy; override; procedure Beschriften(Value:String); override; end; implementation constructor TLabelAnzeige.Create(AOwner:TComponent); begin inherited; FLabel := TLabel.Create(self); end; procedure TLabelAnzeige.Beschriften(Value:String); begin FLabel.Caption := Value; end; destructor TLabelAnzeige.Destroy(Value:String); begin FLabel.Free; inherited; end; constructor TEditAnzeige.Create(AOwner:TComponent); begin inherited Create(AOwner); FEdit := TEdit.Create(self); end; procedure TEditAnzeige.Beschriften(Value:String); begin FEdit.Text := Value; end; destructor TEditAnzeige.Destroy(Value:String); begin FEdit.Free; inherited; end; |
Re: virtual / override ??
@nailor: abstract muss nicht automatisch virtual sein, es kann auch dynamic sein :roll:
|
Re: virtual / override ??
stimmt schon. das wichtige ist (wie ich auch sagte) die platzhalter-eigenschaft der abstrakten methode.
@leuselator: *iii* alles in eine unit gequetscht! |
Re: virtual / override ??
da war wohl einer schneller...
Egal - zu reintroduce: Wenn man eine Vorfahrmethode ohne Angabe von "override" überschreibt, dann "verdeckt" man somit die Vorfahrmethode (und kann sie auch nicht mit "inherited" aufrufen). Der Compiler warnt uns in diesem Fall. Wenn wir uns aber der Konsequenz des Verdeckens bewusst sind (und vielleicht auch genau das erreichen wollen), dann schreiben wir hinter die MethodenDeklaration "reintroduce" - und schon geht der Compiler davon aus, das ein Crack an der Tastatur hockt :-) |
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
biete über 50.000 in meiner derzeit größten :mrgreen:
|
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Hier herrscht mittlerweile einiges an Durcheinander. 8) "abstract" Deklarationen dürfen keine Implementierung implementieren. :mrgreen: Zumindest nicht in der Basisklasse.
Es geht hierbei nur um die Deklaration im class-"Kopf". Damit man es später ersetzen kann. "Virtual" dient zum späteren vererben von Methoden. Hierbei kann man dann auch eine Basis-Methode direkt implementieren. Dann muß das abstract eben entfallen. |
Re: virtual / override ??
wo wir gerade beim thema sind.... wer benutzt eigentlich noch "dynamic" anstelle von "virtual" ?
soweit ich weiss macht es nämlich oberflächlich garkein unterschied (läuft nur intern anders ab)...zudem ist dynamic ja langsamer als virtual....auch wenn kaum merkbar <g> |
Re: virtual / override ??
Die Delphi-Hilfe gibt über die Unterschiede leider nur folgende Auskunft:
Zitat:
|
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Zitat:
Ich mein damit die Ausrichtung an 1-, 2- oder 4-Byte-Grenzen. Auf einem 32-Bit-Prozessor ist ein "Wort" 4 Byte lang, deshalb der Name (auch wenn in den Programmiersprachen, die ich kenne, der Begriff "Wort" bzw. "Word" auf 16 Bit beschränkt ist :? ). |
Re: virtual / override ??
Gut, das ist theoretische Theorie. :P Wer hat mehr zu bieten ? Virtual und abstract sind soweit klar. Was gibts noch ? Es geht allerdings um die praktische Verwendung. Was ist nun mit "reintroduce" und "override". Wann kann/sollte man das verwenden ?
|
Re: virtual / override ??
Zitat:
Code:
So, und nur so kenne ich das; und dies ist von der Prozessorarchitektur nur in so fern abhängig, wie groß ein Byte definiert ist - und das ist bei allen mir bekannten 8 Bit.
1 Byte = 8 Bit
1 Word = 2 Byte = 16 Bit 1 DWord = 2 Word = 4 Byte = 32 Bit // D(ouble)Word 1 QWord = 2 DWord = 4 Word = 8 Byte = 64 Bit // Q(uad)Word gruss, dizzy \\edit: Pre-Tags \\noch mehr Edits: Kleinigkeiten :roll: |
Re: virtual / override ??
Eigentlich ist es ganz simpel, wenn man den Überblick hat:
Es gibt grundsätzlich die Unterscheidung zwischen statischen und virtuellen Methoden. Die dynamischen rechne ich jetzt den virtuellen zu, da diese sich im Laufzeitverhalten nicht von den virtuellen unterscheiden. Klassen sind im wesentlichen nichts weiter als erweiterte Records. Eine Klasse enthält zunächst einen Zeiger auf die Virtual Method Table, dann die Felder und dann die Methoden. Statische Methoden heißen statisch, weil ihre Adresse zur Compilierzeit feststeht. Eine statische Methode wird vom Compiler also wie eine gewöhnliche Funktion behandelt, wenn der Code erzeugt wird. Es wird nur zusätzlich eine Referenz auf das bezogene Objekt mitgegeben. Bei virtuelle Methoden dagegen wird erst zur Laufzeit die Adresse ermittelt. Das geschieht mit Hilfe der VMT (s.o)., in der u.a. die Adressen der virtuellen Methoden stehen. Nun schaue man sich folgendes an:
Delphi-Quellcode:
type
TMyStaticClass = class public procedure DoSomething; end; TMyStaticDerivedClass = class public procedure DoSomething; end; TMyVirtualClass = class public procedure DoSomething; virtual; end; TMyVirtualDerivedClass = class public procedure DoSomething; override; end; procedure TMyStaticClass.DoSomething; begin ShowMessage('1'); end; procedure TMyStaticDerivedClass.DoSomething; begin ShowMessage('2'); end; procedure TMyVirtualClass.DoSomething; begin ShowMessage('3'); end; procedure TMyVirtualDerivedClass.DoSomething; begin ShowMessage('4'); end; So, jetzt probieren wir etwas rum:
Delphi-Quellcode:
Hier wird '1' ausgegeben. Warum, es wird doch eine Instanz von TMyStaticDerviedClass erzeugt? Ja, aber der Typ der Variablen ist TMyStaticClass, und Typen werden zur Compilierzeit ausgewertet.
var
o: TMyStaticClass; begin o := TMyStaticDerivedClass.Create; o.DoSomething; end; Schauen wir uns das ganze mal virtuell an:
Delphi-Quellcode:
Hier wird nun 4 ausgegeben. Wir erinnern uns, jedes Objekt enthält einen Zeiger auf die VMT. Dadurch kann zur Laufzeit, obwohl der tatsächliche Typ unbekannt bzw. maskiert ist, die Adresse der entsprechenden virtuelle Methode ermittelt werden.
var
o: TMyVirtualClass; begin o := TMyVirtualDerivedClass.Create; o.DoSomething; end; Nun zu override: Um zu kennzeichnen, dass wir eine virtuelle Methode überschreiben wollen, müssen wir dem override angeben. Die Methode bleibt dadurch virtuell, keine Angst. Geben wir aber kein override an, so verdecken wir die virtuelle Methode. Der Compiler teilt uns das mit, weil er denkt, wir wollen das nicht so. Wenn wir das aber doch wollen, müssen wir ihm das explizit sagen, und dafür ist reintroduce da. |
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Hier mal dazu der Auszug bei Wikipedia:
![]() Könnte durchaus stimmen. Sowas passiert, wenn eine Wissenschaft mit Lichtgeschwindigkeit aus den Universitäten in die Wirtschaft braust 8) |
Re: virtual / override ??
Ist doch immer wieder schön, wenn 2 gegensätzliche Meinungen derart zusammengeführt werden können, dass keiner von seiner Position abrücken muss, und trotzdem beide Recht erhalten :mrgreen: :stupid:
Dass die Macianer da komisch sind war ja wieder klar... (jaja, ich weiss, eigentlich machen sie's richtig...) |
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Hi!
Eigentlich hat Chewie doch alles erklärt?! Was ist dir noch unklar? Ciao Frederic |
Re: virtual / override ??
mit override überschreibst du die (in diesem fall) prozedur des vorgängers, d.h du kannst die vorgänger prozedur mit "inherited prozedur" aufrufen und noch "eigenes zeugs" mit rein machen.... würdest du kein override benutzen, würde die alte prozedur durch deine neue ersetzt werden und den vorgänger könntest du nichtmehr aufrufen (wenn was falsch war, bitte sagen^^)
|
Re: virtual / override ??
Also : "abstract" darf in der Basisklasse nicht implementiert werden. Es ist wie der Name schon sagt abstrakt. Vorerst also ohne konkrete Bedeutung. In abgeleiteten Klassen kann sich das ändern.
Nun habe ich allerdings keine Lust etwas eventuell überflüssiges zu programmieren. Deshalb verwende ich jetzt nur "virtual", um die Grundlage der Vererbung zu schaffen. Die Basisklasse wird also schon für einen konkreten Zweck gefüllt und kann bei Bedarf überschrieben werden. "abstract" ist eher was für Komponentenentwickler, die beim besten Willen nicht wissen können, was später daraus wird. Da geht es mehr oder weniger nur darum, den Namen einer Methode zu reservieren. Nun aber, was ist mit "override" :?: |
Re: virtual / override ??
override braucht man normal nicht. das ist nur dann zu gebrauchen, wenn du bewusst in einer abgeleiteten klasse etwas von der basisklasse ÜBERSCHREIBEN willst. also nicht hinzufügen sondern WEGMACHEN.
abstract/virtual hat gegenüber nur virtual den vorteil, dass bei virtual in der abgeleiteten version nichts hinzugefügt werden muss, man also theoretisch eine instanz von einem objekt mit nur gerüst-funktion erstellen kann. hängt noch ein abstract dran, kann man zwar zunächst nichts programmieren, aber man kann vin den abgeleiteten klassen keine instantiieren, falls nicht jede abstrakte funktion "overrided" ist - d.h. programmiert wurde, |
Re: virtual / override ??
Wie gesagt, die Prozeduren bleiben bei mir nicht komplett leer, deshalb brauche ich das abstract nicht.
Allerdings habe ich nun noch folgendes bemerkt : dekllariere ich eine Methode als virtual, so wird die abgeleitete Methode nicht ausgeführt (die ebenfalls als virtual deklariert ist). Deklariere ich die abgeleitete dagegen als "override", so wird sie ausgeführt. Hierüber müßte ich schon Klarheit haben. |
Re: virtual / override ??
Lies bitte nochmal meinen Post Hansa - dort ging ich auf alle Deine Fragen ein.
Noch ein Beispiel für Override (Konstruktoren etc. weggelassen):
Delphi-Quellcode:
Gruß
TMensch = Class(TObject)
FGroesse : Integer; FGeburtstag : TDateTime; FAugenfarbe : TColor; FVorname : String; FName : String; public procedure Assign(Value: TMensch); virtual; // nicht abstrakt, da echte Funktionalität // darin steckt property Groesse : Integer read FGroesse write FGroesse; property Geburtstag : TDateTime read FGeburtstag write FGeburtstag; property Augenfarbe : TColor read FAugenfarbe write FAugenfarbe; property Vorname : String read FVorname write FVorname; property Name : String read FName write FName; end; TFrau = class(TMensch) FAnzahlSchuhe : LongInt; // :-) FGeburtsName : String; public procedure Assign(Value: TMensch); override; // damit wir die in TMensch erledigte // Arbeit hier wiederverwenden können property AnzahlSchuhe : LongInt read FAnzahlSchuhe write FAnzahlSchuhe; property GeburtsName : String read FGeburtsName write FGeburtsName; end; TMann = class(TMensch) FAlimenteZahler : Boolean; public procedure Assign(Value: TMensch); reintroduce; // kein "override" (!), löscht bzw. verdeckt // die ererbte Methode. Um CompilerWarnung // zu unterdrücken, Angabe von "reintroduce" property AlimenteZahler:Boolean read FAlimenteZahler write FAlimenteZahler; end; implementation procedure TMensch.Assign(Value:TMensch); begin FGroesse := Value.Groesse; FGeburtstag := Value.Geburtstag; FAugenfarbe := Value.Augenfarbe; FVorname := Value.Vorname; FName := Value.Name; end; procedure TFrau.Assign(Value: TMensch); begin inherited Assign(Value); // Groesse etc. wird abgelegt // geringer Aufwand hier, da Vorfahrklasse die Arbeit erledigt if (Value is TFrau) then begin FAnzahlSchuhe := TFrau(Value).AnzahlSchuhe; end else raise Exception.Create('Dieser Mensch ist keine Frau!'); end; procedure TMann.Assign(Value: TMensch); begin // wir können die ererbte Methode TMensch.Assign nicht aufrufen, // da die TMann.Assign-Methode diese verdeckt! Also müssen wir uns // hier erneut um den Kram kümmern: FGroesse := Value.Groesse; FGeburtstag := Value.Geburtstag; FAugenfarbe := Value.Augenfarbe; FVorname := Value.Vorname; FName := Value.Name; if (Value is TMann) then begin FAlimenteZahler := TMann(Value).AlimenteZahler; end else raise Exception.Create('Dieser Mensch ist kein Mann!'); end; |
Re: virtual / override ??
@nailor: Du liegst leider falsch -das weglassen von override verhindert eben den ererbten Aufruf der Vorfahrmethode - sie wird also verdeckt - nur wenn override angegeben wird, hat man in dem abgeleiteten Objekt über "inherited" (engl. für "ererbt") noch die Zugriffsmöglichkeit auf die Methode des Vorfahrobjektes.
Gruß |
Re: virtual / override ??
Nun mal schön langsam. gaaaanz langsam. 8) Ich deklariere eine Methode also als "virtual". Insofern will ich sie vererben. Im Falle von "override" scheint es so zu sein, daß sie ersatzlos gestrichen wird und durch einen neuen Inhalt ersetzt wird.
Was nun, wenn ich in der Basisklasse schreibe i := 1; und dann noch ein paar Initialisierungen vornehme. In einer abgeleiteten Klasse soll alles bleiben, wie es ist, nur i := 2; soll gemacht werden. In diesem Fall nützt es wenig, alles andere ersatzlos zu streichen. Was ist dann zu tun ? |
Re: virtual / override ??
Zitat:
|
Re: virtual / override ??
Zitat:
Zitat:
|
Re: virtual / override ??
Eventuell auch mal einen Blick in das entsprechende Tutorial von mir werfen, obwohl so detailiert bin ich darauf nicht eingegangen. ;)
|
Re: virtual / override ??
es geht weiter :
reintroduce fast abgehakt, sofern das hier so stimmt: ich erweitere Leusels Bsp. um ein Adoptivkind (Kanzler sei Dank 8) ), von dem das Geburtsdatum nicht genau feststeht. Sagen wir, es ist ein Mädchen, also vom Typ TFrau. In diesem Fall ist das Geburtsdatum irrelevant. TFrauAdoptiv soll nur das Geburtsjahr beinhalten. Ich steige also mit "reintroduce" neu in die Vererbungskette ein. Also TMensch -> TFrau -> TFrauAdoptiv als "reintroduce", was dann allerdings bedeutet, daß alle bereits in TMensch und danach deklarierten Eigenschaften neu definiert (zumindest initialisiert) werden müssen :?: dynamic abgehakt, wegen Überflüssigkeit. :mrgreen: overload nicht abgehakt Ist zwar soweit klar, aber ich habe mir das MessageDlg mal näher angesehen. Das ist auch "overload", d.h. die Parameterliste wird flexibel. Nun stellt sich für mich folgende Frage : Mich hat immer schon gewundert, daß "writeln" egal war, ob ein integer, ein string oder sonstwas angezeigt werden sollte. Geht das Overload in diese Richtung ? noch was ? |
Re: virtual / override ??
overload: mehere namensgleiche funktionen, die allerdings unterschiedliche datentypen erwarten. z.b. kannst du display für strings und ints proggen und überladen. wird dann display mit einem string aufgerufen, machst du showmessage(string), bei einem int machst du showmessage(inttostr(int)). natürlich könntest du auch kommplett unterschiedliche sachen machen...
|
Re: virtual / override ??
@Hansa verdeckt: siehe Zeilen 31ff und 58ff in meinem letzten Codebeispiel!
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz