Thread View: de.comp.lang.c++
6 messages
6 total messages
Started by Detlef Volk
Mon, 26 Feb 1996 15:06
Frage zu C++-Funktionsadresse
Author: Detlef Volk
Date: Mon, 26 Feb 1996 15:06
Date: Mon, 26 Feb 1996 15:06
38 lines
1361 bytes
1361 bytes
Hallo Leute!
Ich habe ein Problem !
Folgender Sachverhalt:
Ich moechte von der Funktion einer Klasse die Adresse in
eine Tabelle ablegen. Ueber den Adressoperator & ist dies nicht moeglich,
da ich die Funktion nicht 'static' machen moechte.
Beispiel:
im Header:
class TBsp {
void Fkt(void);
void BspFkt(void);
};
im CPP-File:
typedef void (* VOIDFKT)(void);
...
void TBsp::Fkt(void) {
VOIDFKT Beispiele[20];
...
Beispiele[0]= &TBsp::BspFkt; <- Compilerfehler !
...
}
Das Problem besteht also darin, dass vom Compiler
beim Adressoperator & die Adresse direkt in den Maschinencode ein-
geschrieben wird, aber die kann der Compiler nicht erzeugen, da sie erst
zur Laufzeit feststeht.
Ich benoetige also eine Funktion, welche waehrend der Laufzeit die
aktuelle Anfangsadresse der Funktion zurueckgibt.
Wer kann mir helfen !
Danke im voraus !
Detlef
Re: Frage zu C++-Funktionsadresse
Author: Dietmar Kuehl
Date: Tue, 27 Feb 1996 17:37
Date: Tue, 27 Feb 1996 17:37
179 lines
5669 bytes
5669 bytes
Hi,
Detlef Volk (detlef.volk@shl.tu-ilmenau.de) wrote:
: Ich moechte von der Funktion einer Klasse die Adresse in
: eine Tabelle ablegen. Ueber den Adressoperator & ist dies nicht moeglich,
: da ich die Funktion nicht 'static' machen moechte.
Die Adresse, die Du haben moechtest, ist ein 'Pointer-to-Member' und
ist als solcher nicht genau dasselbe wie ein "normaler"
Funktionspointer.
: Beispiel:
: im Header:
: class TBsp {
: void Fkt(void);
: void BspFkt(void);
: };
: im CPP-File:
: typedef void (* VOIDFKT)(void);
: ...
: void TBsp::Fkt(void) {
: VOIDFKT Beispiele[20];
: ...
: Beispiele[0]= &TBsp::BspFkt; <- Compilerfehler !
: ...
: }
'&TBsp::BspFkt' hat nicht den Typ 'VOIDFKT', sondern den Typ 'void
(TBsp::*)(void)'. Es gibt also einen Typkonflikt. Man kann die
Memberfunktionen mittels der Pointer-to-Member auch nicht ganz normal
aufrufen, sondern muss sie mit dem '.*' oder dem '->*' Operator
aufrufen, z.B.:
void f(TBsp &obj, void (TBsp::*fkt)(void))
{
(obj.*fkt)()
}
Ananlog wird '->*' verwendet, wenn man einen Pointer anstatt einem
Objekt oder einer Referenz hat. Der Grund fuer diese Konstruktion ist,
dass die Memberfunktionen einen impliziten 'this'-Pointer haben. Das
Objekt, auf dass 'this' zeigt, muss irgendwo angegeben werden.
: Das Problem besteht also darin, dass vom Compiler
: beim Adressoperator & die Adresse direkt in den Maschinencode ein-
: geschrieben wird, aber die kann der Compiler nicht erzeugen, da sie erst
: zur Laufzeit feststeht.
Das trifft es nicht ganz. Die Kombination von Pointer-to-Member (liegt
zur Compiler- bzw. Linkzeit fest) und Objekt (wird erst zur Laufzeit
bestimmt) ist erst zur Laufzeit vorhanden. Um das zu bestimmen, kann
man sich mit einer Klasse helfen, die einen Pointer-to-Member und ein
Objekt (oder einen Pointer auf ein solches) enthaelt. Oft sollen dann
noch Funktionen von verschiedenen Klassen aufgerufen werden (etwa wenn
ein Callback-Mechanismus implementiert wird). Um das auch noch in den
Griff zu bekommen, braucht man eine virtuelle Funktion, die den
entsprechenden Pointer-to-Member aufruft. Hier ist ein Beispiel, wie
man sowas implementieren koennte (leider ist das Beispiel etwas
laenglich; dafuer ist es komplett und laesst sich z.B. mit gcc-2.7.2
compilieren):
#include <iostream.h>
#include <cassert>
class CallbackRC; // this declaration is not really necessary...
class CallbackBase
{
friend class CallbackRC;
private:
int i_refCount; // Used by 'CallbackRC'
public:
CallbackBase(): i_refCount(0) {}
CallbackBase(CallbackBase const &): i_refCount(0) {}
~CallbackBase() { assert(i_refCount == 0); }
CallbackBase &operator= (CallbackBase const &) { return *this; }
virtual void invoke() = 0;
};
class CallbackRC
{
private:
CallbackBase *i_ptr;
public:
CallbackRC(CallbackBase *ptr = 0):
i_ptr(ptr)
{
assert((i_ptr == 0) || (i_ptr->i_refCount == 0));
if (i_ptr != 0)
i_ptr->i_refCount = 1;
}
CallbackRC(CallbackRC const &rc):
i_ptr(rc.i_ptr)
{
assert((i_ptr == 0) || (i_ptr->i_refCount > 0));
if (i_ptr != 0)
++(i_ptr->i_refCount);
}
~CallbackRC()
{
if (i_ptr != 0 && --(i_ptr->i_refCount) == 0)
delete i_ptr;
}
CallbackRC &operator= (CallbackRC const &rc)
{
if (this != &rc)
{
if (i_ptr != 0 && --(i_ptr->i_refCount) == 0)
delete i_ptr;
i_ptr = rc.i_ptr;
assert((i_ptr == 0) || (i_ptr->i_refCount > 0));
if (i_ptr != 0)
++(i_ptr->i_refCount);
}
return *this;
}
CallbackBase &operator* () const { return *i_ptr; }
CallbackBase *operator-> () const { return i_ptr; }
};
template <class T>
class Callback: public CallbackBase
{
private:
T i_obj;
void (T::*i_fkt)(void);
public:
Callback(void (T::*fkt)(void), T const &init = T()):
i_obj(init),
i_fkt(fkt)
{
}
void invoke() { (i_obj.*i_fkt)(); }
};
class Bsp1
{
public:
void fkt1(void) { cout << "Bsp1::fkt1()\n"; }
void fkt2(void) { cout << "Bsp1::fkt2()\n"; }
};
class Bsp2
{
public:
void fkt1(void) { cout << "Bsp2::fkt1()\n"; }
void fkt2(void) { cout << "Bsp2::fkt2()\n"; }
};
int main()
{
CallbackRC list[] =
{
CallbackRC(new Callback<Bsp1>(&Bsp1::fkt1)),
CallbackRC(new Callback<Bsp1>(&Bsp1::fkt2)),
CallbackRC(new Callback<Bsp2>(&Bsp2::fkt1)),
CallbackRC(new Callback<Bsp2>(&Bsp2::fkt2))
};
for (int i = 0; i < sizeof(list) / sizeof(CallbackRC); ++i)
list[i]->invoke();
return 0;
}
Zusaetzlich zu dem, was ich in diesem Artikel beschrieben habe, gibt es
noch Information in dem C++ FAQ in Section 18, etwa unter folgender URL:
<http://www.informatik.uni-konstanz.de/~kuehl/cpp/cppfaq.htm#Q111> (und
folgende FAQs).
--
dietmar.kuehl@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic
Re: Frage zu C++-Funktionsadresse
Author: Dietmar Kuehl
Date: Tue, 27 Feb 1996 18:56
Date: Tue, 27 Feb 1996 18:56
21 lines
1268 bytes
1268 bytes
Hi,
in meinem vorherigen Artikel habe ich einen ueblen Fehler:
Dietmar Kuehl (kuehl@horn.informatik.uni-konstanz.de) wrote:
: class CallbackBase
: {
// ....
: ~CallbackBase() { assert(i_refCount == 0); }
: };
Der Destruktor dieser Klasse muss 'virtual' sein! Es werden (in
'CallbackRC') Objekte von abgeleiteten Klassen durch einen Pointer zu
dieser Basisklasse 'delete'd. Damit das funktioniert, d.h. dass auch
die Destruktoren der abgeleiteten Klasse aufgerufen werden, ist das
'virtual' notwendig (ich glaube, ohne 'virtual' ist das Ergebnis
"undefined behavior").
--
dietmar.kuehl@uni-konstanz.de
http://www.informatik.uni-konstanz.de/~kuehl
I am a realistic optimist - that's why I appear to be slightly pessimistic
Re: Frage zu C++-Funktionsadresse
Author: Detlef Volk
Date: Wed, 28 Feb 1996 06:21
Date: Wed, 28 Feb 1996 06:21
10 lines
950 bytes
950 bytes
Vielen Dank fuer deine Bemuehungen ! Das Ergebnis soll eine Feld mit vielen Funktionen aus unterschiedlichen Klassen sein, welches ich dann als Art Sprungverteiler benutzen moechte. Das ich dafuer allerdings soviel Zeilen benötige, hatte ich nicht erwartet. Ich werde es natuerlich ausprobieren. Also nochmal vielen Dank fuer die Auskunft. Detlef.Volk@shl.tu-ilmenau.de
Re: Frage zu C++-Funktionsadresse
Author: Detlef Volk
Date: Wed, 28 Feb 1996 06:23
Date: Wed, 28 Feb 1996 06:23
10 lines
950 bytes
950 bytes
Vielen Dank fuer deine Bemuehungen ! Das Ergebnis soll eine Feld mit vielen Funktionen aus unterschiedlichen Klassen sein, welches ich dann als Art Sprungverteiler benutzen moechte. Das ich dafuer allerdings soviel Zeilen benötige, hatte ich nicht erwartet. Ich werde es natuerlich ausprobieren. Also nochmal vielen Dank fuer die Auskunft. Detlef.Volk@shl.tu-ilmenau.de
Re: Frage zu C++-Funktionsadresse
Author: Dietmar Kuehl
Date: Wed, 28 Feb 1996 20:48
Date: Wed, 28 Feb 1996 20:48
15 lines
1310 bytes
1310 bytes
Hi, Detlef Volk (detlef.volk@shl.tu-ilmenau.de) wrote: : Das ich dafuer allerdings soviel Zeilen benötige, hatte ich nicht : erwartet. Ich werde es natuerlich ausprobieren. Nun, mit einer vorgefertigten Klasse fuer 'reference counted pointer' wuerde der groesste Teil eh wegfallen. Ich werde mal sehen, dass ich meine Pointer-Klassen etwas auf Vordermann bringe und poste... (derzeit gibt es nur etwas aeltere Versionen von 'auto_res' und 'rc_res' ueber WWW: <http://www.informatik.uni-konstanz.de/~kuehl/c++/auto_res.h.html> bzw. <http://www.informatik.uni-konstanz.de/~kuehl/c++/rc_res.h.html>). -- dietmar.kuehl@uni-konstanz.de http://www.informatik.uni-konstanz.de/~kuehl I am a realistic optimist - that's why I appear to be slightly pessimistic
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads