Autor Beitrag
Klabautermann
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Veteran
Beiträge: 6366
Erhaltene Danke: 60

Windows 7, Ubuntu
Delphi 7 Prof.
BeitragVerfasst: Do 10.04.03 14:19 
Hallo,

ich habe mal eine verständnifrage zum zuweisen von Ereignisbehandlungsmethoden.

Angenommen ich möche einen Menüpunkt eine Methoe zuweisen. Dann geht das wenn es so aussieht:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
tMyObj : class(tObject)
private
  procedure MyClick(Sender: TObject);
[...]
procedure tMyObj.SetOnClick;
begin
  MyMenu.OnClick := MyClick;
end;


Es funktioniert aber nicht, wenn das ganze so aussieht:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
tMyObj : class(tObject)
  [...]
end; // Ende der Klassendefinition

procedure MyClick(Sender: TObject);
[...]
procedure tMyObj.SetOnClick;
begin
  MyMenu.OnClick := MyClick;
end;

Meine Frage ist nun, warum ist das so? Eigentlich kann es dem Compiler doch völlig schnuppe sein ob die Methode zu dem Objekt gehört oder ob sie "frei" ist.

Neugierig
Klabautermann
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 10.04.03 14:31 
Eigentlich schon, darüber bin ich auch öfters gestolpert.

Zum Begriff "Methode": Eine Methode ist grundsätzlich eine Prozedur oder Funktion eines Objekts, während alles andere dann als normale Prozedur oder Funktion bezeichnet wird.

Tatsache ist, das Platzhalter für Ereignisse (z.B. eine Variable vom Typ TNotifyEvent) nur das eine oder das andere akzeptieren, abhängig davon, ob dieser Ereignistyp mit dem Zusatz "of object" oder nicht deklariert wurde.

Da TNotifyEvent so deklariert ist
ausblenden Quelltext
1:
type TNotifyEvent = procedure(Sender:TObject) of object;					

lassen sich nur Methoden zuweisen.

Die Delphihilfe lässt sich darüber leider nicht aus. Der einzige Satz darüber ist folgender:
Zitat:
Zeiger auf Prozeduren sind niemals kompatibel zu Zeigern auf Methoden.


Cu,
Udontknow
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Do 10.04.03 14:54 
Udontknow hat folgendes geschrieben:
Die Delphihilfe lässt sich darüber leider nicht aus. Der einzige Satz darüber ist folgender:
Zitat:
Zeiger auf Prozeduren sind niemals kompatibel zu Zeigern auf Methoden.

Ein bisschen mehr steht schon drinnen, man muss nur ein bisschen suchen..!

Ich hab mich relativ ausführlich damit beschäftigt als ich mein Spezialgebiet für meine Matura (österr. Version des Abit) geschrieben hab (mein Thema war "OOP in Delphi").
Methodenzeiger sind anders aufgebaut als Prozedurzeiger. Während Prozedurzeiger nur einen Zeiger darstellen, der an die Stelle im Speicher zeigt an der der Code steht bestehen Methodenzeiger eigentlich aus 2 Pointern. Einer zeigt an die Stelle im Speicher wo der Code ist, während der andre Pointer das Objekt selbst referenziert. Der 2te Pointer stellt also den "Selbst-Zeiger" Self dar. Das ganze kann man relativ leicht nachvollziehn, wenn man eine Methode die den Pointer Self verwendet mal im CPU-Fenster betrachtet. Der Self-Pointer wird immer in eax übergeben, damit die Methode "weiß" zu welchem Objekt sie jetzt eigentlich gehört.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 10.04.03 15:05 
Ja, das macht Sinn. Wo finde ich denn näheres dazu in der Delphi-Hilfe?
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Do 10.04.03 15:16 
Udontknow hat folgendes geschrieben:
Ja, das macht Sinn. Wo finde ich denn näheres dazu in der Delphi-Hilfe?

Weiß nicht genau.. hab jetzt grad auch keine Delphi-Hilfe zur Hand, aber schau mal unter Pointer, Methodenzeiger, Prozedurzeiger, ... sowas in der Richtung.
Wenn ich zu Hause bin kann ich dir mehr dazu sagen und eventuell auch einen Link zu meinem Spezialgebiet posten.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Klabautermann Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Veteran
Beiträge: 6366
Erhaltene Danke: 60

Windows 7, Ubuntu
Delphi 7 Prof.
BeitragVerfasst: Do 10.04.03 15:39 
Hallo,

das war schon mal sehr interessant.
Danke euch beiden.

Gruß
Klabautermann
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Do 10.04.03 17:55 
Hier mal das Zitat aus meiner Delphi-Hilfe:
Zitat:
Procedural types allow you to treat procedures and functions as values that can be assigned to variables or passed to other procedures and functions. For example, suppose you define a function called Calc that takes two integer parameters and returns an integer:

ausblenden Quelltext
1:
function Calc(X,Y: Integer): Integer;					


You can assign the Calc function to the variable F:

ausblenden Quelltext
1:
2:
3:
var F: function(X,Y: Integer): Integer;

F := Calc;


If you take any procedure or function heading and remove the identifier after the word procedure or function, what?s left is the name of a procedural type. You can use such type names directly in variable declarations (as in the example above) or to declare new types:

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
type

  TIntegerFunction = function: Integer;
  TProcedure = procedure;
  TStrProc = procedure(const S: string);
  TMathFunc = function(X: Double): Double;
var
  F: TIntegerFunction;             { F is a parameterless function that returns an integer }
  Proc: TProcedure;                { Proc is a parameterless procedure }
  SP: TStrProc;                    { SP is a procedure that takes a string parameter }
  M: TMathFunc;                    { M is a function that takes a Double (real) parameter 

                                       and returns a Double }
procedure FuncProc(P: TIntegerFunction);  { FuncProc is a procedure whose only parameter 
                                              is a parameterless integer-valued function }


The variables above are all procedure pointers?that is, pointers to the address of a procedure or function. If you want to reference a method of an instance object (see Classes and objects), you need to add the words of object to the procedural type name. For example

ausblenden Quelltext
1:
2:
3:
4:
type

  TMethod = procedure of object;
  TNotifyEvent = procedure(Sender: TObject) of object;


These types represent method pointers. A method pointer is really a pair of pointers; the first stores the address of a method, and the second stores a reference to the object the method belongs to. Given the declarations

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
type

  TNotifyEvent = procedure(Sender: TObject) of object;
  TMainForm = class(TForm)
    procedure ButtonClick(Sender: TObject);
    ...
  end;
var
  MainForm: TMainForm;
  OnClick: TNotifyEvent


we could make the following assignment.

ausblenden Quelltext
1:
OnClick := MainForm.ButtonClick;					


Two procedural types are compatible if they have

the same calling convention,
the same return value (or no return value), and
the same number of parameters, with identically typed parameters in corresponding positions. (Parameter names do not matter.)

Procedure pointer types are always incompatible with method pointer types. The value nil can be assigned to any procedural type.
Nested procedures and functions (routines declared within other routines) cannot be used as procedural values, nor can predefined procedures and functions. If you want to use a predefined routine like Length as a procedural value, write a wrapper for it:

ausblenden Quelltext
1:
2:
3:
4:
5:
function FLength(S: string): Integer;

begin
  Result := Length(S);
end;

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Do 17.04.03 15:52 
So, und für diejenigen dies noch interessiert - hier www.x-spy.net/personal kann man sich meine Ausarbeitung über OOP in Delphi runterladen...

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!