Autor Beitrag
delphisual
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 89

WIN 2000
D5 Prof
BeitragVerfasst: Do 05.02.04 19:52 
Hallo zusammen,
ich habe ein Paar Fragen bezüglich OOP um genauer zu sein beziehen sich meine Fragen eher auf die Methoden in OOP.

Wo liegt der unterschied zwischen virtuellen und statischen Methoden?

Ich weis dass auf virtuellen Methoden über eine VMT zugegriffen wird und die Statischen Methoden direkt angesprochen werden.
Ich bin bis jetzt immer davon ausgegangen das die Virtuellen Methoden extra für die überschreibung, von Methoden des Vorfahren durch die Gleichnamige Methoden des Nachfahren, bestimmt sind.
Es scheint aber genau andersrum zu sein!?

Beispiel1:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
unit uMutter;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

  type
  TMutter = class(TObject)
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  procedure Alter;

  end;

implementation

procedure TMutter.Alter;
begin
ShowMessage('Alter ist 45');
end;
end.




unit uKind;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  uMutter;

  type
  TKind = class(TMutter)
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  procedure Alter;

  end;

implementation

procedure TKind.Alter;
begin
ShowMessage('Alter ist 15');
end;



end.





unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses uMutter,uKind;

procedure TForm1.Button1Click(Sender: TObject);
var Mutter: TMutter;
    Kind: TKind;
begin
Mutter:=TMutter.Create;
Mutter.Alter;
Kind:=TKind.Create;
Kind.Alter;
end;

end.


Nach dem Compilieren habe ich festgestellt das die Methode TMutter.Alter von TKind.Alter überschrieben wurde, ob woll ich die Methode nicht als virtual deklariert habe!

Beispiel2:
Ich habe die Methode TMutter.Alter an TKind vererbt und die erweitert:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure TKind.Alter;
begin
inherited;
ShowMessage('Alter ist 15');
end;

Funktioniert auch ohne direktive virtual!

Beispiel3:
Ich erzeuge das Objekt Mutter mit dem Zeiger auf TKind Klasse.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.Button1Click(Sender: TObject);
var Mutter: TMutter;
    Kind: TKind;
begin
Mutter:=TKind.Create;
Mutter.Alter;
end;

das Funktioniert doch ich habe trotzdem die Methode von TMutter.Alter ausgelesen!

Kenzeichne ich die Methode TMutter.Alter mit virtual, und die Methode TKind.Alter mit override, lese ich (mit dem gleichen Code) dann die Methode des TKind.Alter aus.

?: Ich habe bis jetzt immer gedacht dass, wenn ich die Methode des Vorfahren überschreiben will, ich muss die deklaration mit virtual und override machen .


1. Wie ich aber festgestellt habe hat die deklaration nur dan die wirkung wenn ich die die Methoden des Nachfahrens auslese!???

2. Wie es aussieht kann ich nicht mit statischen Methoden auf die Methoden des Nachfahrens zugreifen aber warum soll ich das wollen?


3. Bitte schreibt mir die Einatzgebiete der Statischen und virtuellen Methoden, ich weis nicht mehr weiter.


MfG
delphisual

Moderiert von user profile iconPeter Lustig: Topic verschoben

_________________
(Wer ein Problem definiert, hat es schon halb gelöst.)
ChrHohbein
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Do 05.02.04 20:04 
Zu Beispiel 3.
Du hast Das objekt mutter als Objekt TMutter deklariert.
Du kannst für die die Zuweisung natürlich ein objekt nehmen was von diesesm Abgeleitet ist. er wirt für die Verwendung aber lediglich die Klasse nehmen die du ihm vorher zugewiesen hast nämlich TMutter.
MSCH
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1448
Erhaltene Danke: 3

W7 64
XE2, SQL, DevExpress, DevArt, Oracle, SQLServer
BeitragVerfasst: Do 05.02.04 21:57 
Zitate:
Zitat:
Mit Hilfe der Direktiven virtual und dynamic können Methoden als virtuell oder dynamisch deklariert werden. Virtuelle und dynamische Methoden können im Gegensatz zu statischen Methoden in abgeleiteten Klassen überschrieben werden. Beim Aufrufen einer überschriebenen Methode bestimmt nicht der deklarierte, sondern der aktuelle Typ (also der Typ zur Laufzeit) der im Aufruf verwendeten Klassen- bzw. Objektvariable, welche Implementierung aktiviert wird.
Um eine Methode zu überschreiben, braucht sie nur mit der Direktiven override erneut deklariert zu werden. Dabei müssen Reihenfolge und Typ der Parameter sowie der Typ des Rückgabewertes (falls vorhanden) mit der Deklaration in der Vorfahrklasse übereinstimmen.


Zitat:
Unterschiede zwischen virtuellen und dynamischen Methoden

Virtuelle und dynamische Methoden sind von der Semantik her identisch. Sie unterscheiden sich nur bei der Implementierung der Aufrufverteilung zur Laufzeit. Virtuelle Methoden werden auf Geschwindigkeit, dynamische Methoden auf Code-Größe optimiert.
Im allgemeinen kann mit virtuellen Methoden polymorphes Verhalten am effizientesten implementiert werden. Dynamische Methoden sind hilfreich, wenn in einer Basisklasse eine große Anzahl überschreibbarer Methoden deklariert ist, die von vielen abgeleiteten Klassen geerbt, aber nur selten überschrieben werden.


näheres in der OH.
grez
msch

_________________
ist das politisch, wenn ich linksdrehenden Joghurt haben möchte?
delphisual Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 89

WIN 2000
D5 Prof
BeitragVerfasst: Do 05.02.04 22:26 
Danke erstmal für Eure Antworten,
ich habe die Delphi Hilfe selber schon paar mal durchgelesen. Es ist mir auch bekannt das die dynamische Methoden bei ca. 100 Methoden 40 kb einsparen, doch es geht mir nicht darum! Mich interessiert einfach wofür ich genau die Fähigkeit brauche aus dem Mutter Objekts-Methode auf die Methode des Kinds-Objekt zuzugreifen. Den wenn ich einfach nur die Methode des Vorfahren im Nachfahr-Objekt nutzen will brauche ich keine virtuelle Deklaration, möchte ich aber auf die Methode des Nachkommen aus dem Objekt des Vorfahren zugreifen so ist die virtual Deklaration der Methode ein Mus!

Normale weise ist das doch so, dass man mit Nachfahr-Objecten arbeitet die von Vorfahren stammen und nicht andersrum! Es ist auch öfters anzusehen das die Methoden als abstract deklariert werden, da ist aber der Sinn ganz klar Kompatibilität von verschiedenen Nachverfahren zueinander. Werden vielleicht aus dem Gleichen Grund auch die virtuellen Methoden verwendet?

Wozu brauchen im Hierarchie der VCL höher angesiedelte Objekte die Zugriffmöglichkeit auf die weiter unten angesiedelte Objekte, den wie ich es verstehe genau das mache ich mit Deklaration von virtual Methoden?

Mit freundlichen Grüßen
delphisual

_________________
(Wer ein Problem definiert, hat es schon halb gelöst.)
MSCH
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1448
Erhaltene Danke: 3

W7 64
XE2, SQL, DevExpress, DevArt, Oracle, SQLServer
BeitragVerfasst: Do 05.02.04 22:39 
hi, wenn ich's richtig lese, von dem Parent-Object auf Child-Object-Functionen zugreifen? Das geht nicht. Nur umgekehrt.

Eine virtuelle Methode braucht man, wenn man in der abgeleiteten Child-Methode die gleichnamige des Parents aufrufen möchte.
(inherited)

beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
Type
  TmyParent= Class
    Titel: String;
    procedure Paint; virtual;
  end;
  TmyChild = Class(TmyParent)
    procedure Paint;virtual;
  end;

procedure TmyParent.Paint;
begin
  // schreibe jetzt den TItel irgentwo hin, z.b. auf ein Canvas -Beispiel!!
end;

procedure TmyChild.Paint;
begin
  inherited// Aufruf der Parent-Methode also den Titel zeichen
  // aber nun die Funktion erweitern
  // mach noch einen Rahmen um den Titel -Beispiel!!
end;


Simpel aus gedrückt, Basisklassen implementieren nur rudimentär die Funktion; in abgeleiteten Klassen wird diese dann erweitert. Schau dir einfach mal die Quelltexte der VCL an.
grez
msch

_________________
ist das politisch, wenn ich linksdrehenden Joghurt haben möchte?
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Fr 06.02.04 00:23 
MSCH hat folgendes geschrieben:
Eine virtuelle Methode braucht man, wenn man in der abgeleiteten Child-Methode die gleichnamige des Parents aufrufen möchte.
(inherited)

Dazu brauch ich keine virtuelle Methode.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
type
  TBase = class(TObject)
    procedure TuWas;
  end;

  TDerived = class(TBase)
    procedure TuWas;
  end;

procedure TBase.TuWas;
begin
  ShowMessage('Ich mach was.');
end;

procedure TDerived.TuWas;
begin
  inherited TuWas;
end;



Virtuelle Methoden ermöglichen es eine Basisklasse zu schreiben, die es den abgeleiteten Klassen ermöglicht eine bestehende Funktionalität zu erweitern. So weiß z.B. eine Basisklasse TFileStorage wie sie eine einen Stream in eine Datei schreibt. Wie die Daten in den Stream kommen überlässt sie den Unterklassen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
type
  TFileStorage = class(TObject)
    procedure SaveToFile(const FileName: string);
    procedure SaveToStream(Stream: TStream); virtual;
  end;

procedure TFileStorage.SaveToFile(const FileName: string);
var
  Stream: TStream;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  try
    SaveToStream(Stream); // hier wird die virtuelle Methode aufgerufen
  finally
    Stream.Free;
  end;
end;

procedure TFileStorage.SaveToStream(Stream: TStream); 
begin
  // die Unterklassen wissen was sie hier machen müssen
end;

Wenn man nun eine Klasse TPerson von TFileStorage ableitet, und die Methode SaveToStream überschreibt, wird automatisch die TPerson.SaveToStream Methode von TFileStorage.SaveToFile aufgerufen.
Wäre SaveToStream statisch gewesen würde egal wie oft man SaveToStream in einer Unterklasse zu überschreiben versucht immer TFileStorage.SaveToStream aufgerufen, die ja nichts macht.


Anderes Beispiel:
Schleifen sind was feines. Also möchte man seine Daten bzw. Objekte immer gerne in Listen oder Arrays halten um sie mit Schleifen zu durchlaufen. Jetzt wäre es ziemlich umständlich, wenn man ständig mit is Prüfen müsste, dass ein Objekt von Typ TPunkt, TLinie, TRechteck, TKreis ist und dann entsprechend Typecasten. Also führt man alle Gemeinsamkeiten in einer Basisklasse zusammen, die da z.B. wären:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
type
  TDrawable = class(TObject)
     procedure DrawTo(Canvas: TCanvas); virtual;
  end;

Nun kann man seine Unterklassen davon ableiten und DrawTo mit den entsprechenden Zeichenbefehlen überschreiben. Hiermit erlaubt der Compiler uns folgendes zu machen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var a: array[0..3of TDrawable;
begin
  a[0] := TKreis.Create(10105, clRed);
  a[1] := TRechteck.Create(551515, clBlack);
  a[2] := TLinie.Create(551515, clYellow);
  a[3] := TPunkt.Create(1010, clBlue);

  for i := 0 to High(a) do
    a[i].DrawTo(Canvas);
end;

Ohne virtuelle Methoden würde das ungefähr so aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var a: array[0..3of TDrawable;
begin
  a[0] := TKreis.Create(10105, clRed);
  a[1] := TRechteck.Create(551515, clBlack);
  a[2] := TLinie.Create(551515, clYellow);
  a[3] := TPunkt.Create(1010, clBlue);

  for i := 0 to High(a) do
  begin
    if a[i] is TKreis then TKreis(a[i]).DrawTo(Canvas)
    else if a[i] is TRechteck then TRechteck(a[i]).DrawTo(Canvas)
    ...
end;
wobei auf noch auf die richtige Reihenfolge geachtet werden muss, da ein TRechteck z.B. von eine TLinie abgeleitet sein kann, ...
Und was passiert, wenn man nachdem das Programm fertig ist, jetzt auf die Idee kommt, ein weiteres zeichenbares Objekt TDreieck zu erfinden. Man müsste alle Stellen im Programm durchforsten, anpassen und hoffen, dass nicht noch einer einen Einfall für ein zeichenbares Objekt hat.

_________________
Ist Zeit wirklich Geld?
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 06.02.04 12:54 
Kuck mal hier: www.luckie-online.de/files/beta-area/ da steht alles drin. Ist allerdings noch nicht fertig.
delphisual Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 89

WIN 2000
D5 Prof
BeitragVerfasst: Fr 06.02.04 15:36 
Hallo zusammen und danke für Eure Beteilung an der Diskussion!

Ich habe mir heute den ganzen Tag Gedanken drüber gemacht was ich mit dieser Fähigkeit anfangen will, und wenn ich das richtig verstanden habe bin ich in der Lage mir meine eigene Hierarchie so aufzubauen, dass ich von Vorfahr-Objekt auf alle Nachfahr-Objekte ohne Einschränkung zugreifen kann.
Wusste ich gar nicht das die Polymorphie so ein mächtiges Werkzeug ist, ich werde auf jeden Fall mich noch etwas damit beschäftigen.
Vielen, Vielen Dank für Eure Zeit!
super Forum hier.

Mit freundlichen Grüßen
delphisual

_________________
(Wer ein Problem definiert, hat es schon halb gelöst.)