AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Wie wird OOP Compiler intern realisiert?
Thema durchsuchen
Ansicht
Themen-Optionen

Wie wird OOP Compiler intern realisiert?

Ein Thema von Skiron · begonnen am 19. Mär 2004 · letzter Beitrag vom 20. Mär 2004
Antwort Antwort
Skiron

Registriert seit: 14. Dez 2003
153 Beiträge
 
#1

Wie wird OOP Compiler intern realisiert?

  Alt 19. Mär 2004, 13:00
Wie wird eigentlich eine Klasse angelegt?
wird da ca. so der speicher angelegt:
||--Eigenschaften--|--Methoden--||
?
oder wird das so zerlegt:
Delphi-Quellcode:
type
  Ttest = class
    a: integer;
    b: integer;
    function Summe: integer;
  end;

...

function Ttest.Summe: integer;
begin
  result := a + b;
end;

...
var
  h: Ttest;
begin
  h := Ttest.Create;
  h.Summe;
  h.Free;
end;
...
in

Delphi-Quellcode:
tyoe
  Ttest = record
    a: integer;
    b: integer;
  end;

...

function TtestSumme(Value: Ttest): integer;
begin
  with Value do
    result := a + b
end;

...

var
  h: Ttest
begin
  @h = AllocMem(SizeOf(Ttest));
  TtestSumme(h);
  FreeMem(@h);
end;
...
oder ist das zu umstänlich?
wie wird OOP dann CompilerInern realisiert?
Mann zu Frau:
Zieh dich aus, wir müssen reden!
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Wie wird OOP Compiler intern realisiert?

  Alt 19. Mär 2004, 19:39
Wie alles funktioniert, weiß ich nicht, aber ein paar Sachen kann ich dir erklären:

Klassen

Klassen bestehen aus Methoden und Feldern. Während für Felder bei jedem Objekt neuer Speicherplatz alloziert wird, existieren Methoden nur einmal im Speicher. Da eine Methode aber evtl. auf Felder des Objekts zugreift, in dessen kontext sie aufgerufen wurde, muss ja irgendwo einen Bezug zur Klasse existieren. Das wird durch den unsichtbaren Parameter Self bewerkstelligt. Wenn du also folgende Methode hast:
[delphi][pre]procedure TMyClass.SomeMethod(Dummy: Integer);[/pre]
sieht diese in Wirklichkeit so aus:
[delphi][pre]procedure TMyClass.SomeMethod(Self: TMyClass; Dummy: Integer);[/pre]

Der Speicher, den ein Objekt belegt, liegt im Heap. Eine Variable einer Klasse ist nicht das Objekt selbst, sondern nur eine referenz, also ein Zeiger, auf das Objekt. Allerdings merkst du das dank der eingebauten Compiler Magic nicht.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
tommie-lie
(Gast)

n/a Beiträge
 
#3

Re: Wie wird OOP Compiler intern realisiert?

  Alt 19. Mär 2004, 20:25
Also bei Delphi hinke ich mit den Internas noch arg hinterher, aber viele C-Compiler, allen vorran der GCC, benutzen für Klassen tatsächlich recordartige Strukturen. Eine Methode ist da ein Pointer auf eine Funktion.
Dabei werden immer die ältesten Subsets der Klasse nach vorne gepackt, wenn du also eine Klasse von irgendwo ableitest, werden Felder und Methoden nicht sortiert (Felder zuerst, dann erst die Methoden) oder sowas (Methoden zuerst, dann erst die Felder), sondern nur hinten drangehangen. Dadurch ist es dann möglich, einen Typecast in einen Ancestor-Typ zu machen, ohne daß der Compiler für sämtliche Eventualitäten die Strukturen neu schreiben darf.
Erzeugt werden die Klassen dann intern auch mit malloc (bzw was sich sonst so grad' in der C-Library findet), anschließend werden die Pointer auf die Methoden (ebenfalls nur einmal im Speicher) eingerenkt und fertig.
Da ich dieses Prinzip für sehr sinnvoll und effizient halte, vermute ich, daß Borland ähnlich vorgeht und ebenfalls recordähnliche Strukturen für Klassen verwendet.
Der Aufruf von Methoden eines Objektes sieht dann so aus, das man sich den Zeiger schnappt, dereferenziert, die Referenz auf das Objekt als Parameter (user-transparent) übergibt und hinspringt.
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.481 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4

Re: Wie wird OOP Compiler intern realisiert?

  Alt 20. Mär 2004, 13:35
Habe ihr schon mal von der VMT (virtual method table) gehört? Das ist das, was tommie-lie mit dem Eintrenken von Zeigern meint.

Eine Class besteht unter Delphi aus mindestens einem Feld, dem VMT Zeiger. In dieser VMT stehen nun alle Zeiger auf die virtuellen Methoden. Zudem gibt es in der VMT ein Feld für die DMT (dynamic method table), in der eine Liste mit Index<->Methodenzeiger-Abbildungen enthalten ist und ein Zeiger auf die DMT der Oberklasse. Die VMT ist für jede Klasse einmalig und wird bereits durch den Compiler komplett aufgebaut.

Die Klasse TObject kann man folgendermaßen umschreiben (pseudocode):
Delphi-Quellcode:
type
  PVmt = ^TVmt;
  TVmt = array[-19..MaxWord] of Pointer;

  TObject = ^_TObject;
  _TObject = record
    Vmt: PVmt;
  end;
Wenn nun neue Felder hinzukommen, werden diese hinten angehängt.
Delphi-Quellcode:
type
  TMyClass = class(TObject)
    FMyField: Integer;
  end;
Delphi-Quellcode:
type
  TMyClass = record
    Vmt: PVmt;
    FMyField: Integer;
  end;

Wenn eine statische Methode aufgerufen wird, dann wird dieser zusätzlich ein unsichtbarer Parameter Self übergeben, auf den sich dann der Code in der Methode bezieht. Bei virtuellen kann der Linker die Methoden-Adresse nicht einfach einsetzen. Somit muss die Adresse der Methode zur Laufzeit bestimmt werden. Hierzu wird die Methode über die VMT aufgerufen, was ungefähr so in Pascal-Code aussehen würde:
Delphi-Quellcode:
var
  MyInstance: TMyClass;
begin
  ...
  // MyInstance.DoVirtual(10);
  T_DoVirtual_MethodPtr( MyInstance.Vmt[VmtIndexOf(DoVirtual)] )(10);
  ...
end;
Bei dynamischen Methoden ist das noch ein wenig komplizierter, da dort nicht nur in der DMT der aktuellen Klasse gesucht werden muss, sondern, wenn dort kein passender Eintrag gefunden wurde, auch die DMTs der Oberklassen. Das sähe dann ungeführ so aus (pseudocode).
Delphi-Quellcode:
var
  MyInstance: TMyClass;
// <temp>
  Dmt: PDMT;
  Idx: Integer;
// </temp>
begin
  ...
  // MyInstance.DoDynamic(10);
  Dmt := MyInstance.Vmt[System.vmtDynamicTable div SizeOf(Pointer)];
  while (Dmt <> nil) do
  begin
    Idx := 0;
    while (Dmt.Items[Idx].Index <> 0) do
    begin
      if Dmt.Items[Idx].Index = DmtIndexOf(DoDynamic) then
      begin
        T_DoDynamic_MethodPtr( Dmt.Items[Idx].Proc )(10);
        Exit;
      end;
      Inc(Idx);
    end;
    Dmt := Dmt.ParentDmt;
  end;
  ...
end;
Und weil das nicht wenig Code ist, hat Borland diesen Code in the Methode TObject.Dispatch ausgelagert. Zu BorlandPascal Zeiten gab es noch einen Cache für die zuletzt aufgerufene dynamische Methode um den Aufruf zu beschleunigen. In der Delphi-implementierung ist dieser nicht mehr vorhanden.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:34 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz