• Liebe User, bitte beachtet folgendes Thema: Was im Forum passiert, bleibt im Forum! Danke!
  • Hallo Gemeinde! Das Problem leidet zurzeit unter technischen Problemen. Wir sind da dran, aber das Zeitkontingent ist begrenzt. In der Zwischenzeit dürfte den meisten aufgefallen sein, dass das Erstellen von Posts funktioniert, auch wenn das Forum erstmal eine Fehlermeldung wirft. Um unseren Löschaufwand zu minimieren, bitten wir euch darum, nicht mehrmals auf 'Post Reply' zu klicken, da das zur Mehrfachposts führt. Grußworte.

Frage an die C++ Profis bzgl. FunctionPointer

Mitglied seit
04.08.2002
Beiträge
1.869
Reaktionen
0
Moin.

Es geht um FunctionPointer. Ganz einfache Frage:
Ich habe eine Klasse. Innerhalb dieser Klasse gibt es irgendeine Funktion, welche einen Pointer auf eine andere Funktion übergeben bekommen soll und diese dann ausführt.
Soweit alles kein Problem, wenn die zweite Funktion, auf die der übergebene Pointer zeigt, nicht selbst Member-Funktion einer Klasse ist. Denn ansonsten funktioniert das leider nicht so einfach.

Ich habe mittlerweile ein wenig im Internet gestöbert und ein wenig selbst herumexperimentiert und bin mittlerweile soweit, dass es funktioniert, wenn ich mir eine gemeinsame WrapperKlasse baue, beide Funktionen von dieser Klasse ableite und dann den Funktionspointer entsprechend caste... Allerdings ist das mit einer Menge Overhead verbunden, auf den ich gerne verzichten würde.

Also, kennt jemand von Euch eine einfache Möglichkeit, Pointer auf Funktionen über Klassengrenzen hinweg zu übergeben, ohne irgendwelche Third-Party-Libraries etc. zu benutzen und ohne eben den o.g. Umweg über eine WrapperKlasse zu gehen?

Bin da für jeden Tipp dankbar.
Gruß
m.a.k.

P.S.: Hier nochmal ein kleines Codebeispiel, falls oben noch nicht so ganz klar geworden sein sollte, was ich meinte (ist leider nicht korrekt eingerückt, aber ich hoffe, es geht auch so):

class CTest1
{
public:
CTest1(){};
~CTest1(){};

void TestIn(){printf("Erster Test innerhalb der Klasse");};
};

class CTest2
{
public:
CTest2(){};
~CTest2(){};

void TestCall(void(*pfunc)(void))
{
pfunc();
};
};

void TestOut()
{
printf("Zweiter Test außerhalb der Klasse");
}

int main()
{
CTest1 test1;
CTest2 test2;

test2.TestCall(TestOut); // <<== funktioniert ohne Probleme
test2.TestCall(test1.TestIn); // <<== das hier leider nicht

return(0);
}
 
Mitglied seit
04.08.2002
Beiträge
1.869
Reaktionen
0
so, kleiner Nachtrag:

Ich hab jetzt noch mal ein bisschen rumgespielt und bin jetzt im Moment bei folgender Lösung, die mich zwar nicht zu 100% zufrieden stellt, die mein Problem aber löst und den Umweg über eine Wrapper Kasse erspart:

class CTest1
{
public:
CTest1(){};
~CTest1(){};

void TestIn(const char* szBuffer){printf(szBuffer);};
//wrapper function for TestIn
static void TestIn_Wrapper(void *pObject, const char *szBuffer)
{
if((pObject)&&(szBuffer))
{
CTest1* pMyClass = (CTest1*)pObject;
pMyClass->TestIn(szBuffer);
}
};
};

class CTest2
{
private:
void* m_pObject; //pointer to the object containing the function to call
void (*m_pWrapperFunction)(void *pObject, const char* szBuffer); //pointer to the wrapper function

public:
CTest2(){};
~CTest2(){};

void SetCall(void* pObject, void(*pWrapperFunction)(void *pObject, const char* szBuffer))
{
m_pObject = pObject;
m_pWrapperFunction = pWrapperFunction;
}

void ExecCall(const char* szBuffer)
{
m_pWrapperFunction(m_pObject, szBuffer);
};
};

int main()
{
CTest1 test1;
CTest2 test2;

test2.SetCall((void*)&test1, test1.TestIn_Wrapper);
test2.ExecCall("Ich bin ein Test ;)");
return(0);
}


Statt eine Wrapper Klasse zu benutzen, von der ich dann alles ableite, nehme ich also jetzt einfach eine Wrapper Funktion für jede Funktion, die per FunctionPointer übergeben werde können soll, und deklariere diese als static.
Das ist zwar immer noch ein bisschen mehr Aufwand, als ich gerne hätte, aber ich befürchte, noch einfacher krieg ichs nicht.

Also, wenn jemand da noch eine Idee hat, wie es vielleicht noch einfacher bzw. effizienter geht, dann bitte immer raus damit.

Gruß
Markus
 

The_Company

Guest
C++ benutzt als ersten Parameter den this pointer.

Also hat CTest1::TestIn() den Prototype void (*func) (CTest1*) während TestOut() den Prototype void (*func) (void) hat. Und die sind beide unterschiedlich, also gibts nen casting error.

Das ganze hast Du ja dann schön umgangen, indem Du am Anfang immer nen void* mitreinschiebst. Da kannste dann auch den Wrapper weglassen.

Gibts übrigens genug Spass mit Google zu.
 
Mitglied seit
04.08.2002
Beiträge
1.869
Reaktionen
0
Original geschrieben von The_Company
Das ganze hast Du ja dann schön umgangen, indem Du am Anfang immer nen void* mitreinschiebst. Da kannste dann auch den Wrapper weglassen.

Ich weiss jetzt nicht auf welche Stelle Du Dich genau beziehst, da ich an ziemlich vielen Stellen gecastet habe, aber die Wrapper-Klasse bzw. -Funktion kann ich ganz sicher nicht weglassen.
Sollte ich mich da täuschen, dann würde ich Dich bitten, mir mal ein entsprechendes Code-Beispiel zu posten.
 
Mitglied seit
03.08.2002
Beiträge
707
Reaktionen
0
gehts so ?

class CTest1
{
public:
CTest1(){};
~CTest1(){};

void TestIn(){printf("Erster Test innerhalb der Klasse");};
};

class CTest2
{
public:
CTest2(){};
~CTest2(){};

void TestCall(CTest1 *asdf, void(CTest1::*pfunc)(void))
{
(asdf->*pfunc)();
};
};

void TestOut()
{
printf("Zweiter Test außerhalb der Klasse");
}

int main()
{
CTest1 test1;
CTest2 test2;

test2.TestCall(TestOut); // <<== funktioniert ohne Probleme
test2.TestCall(&test1, &CTest1::TestIn); // <<== das hier leider nicht

return(0);
}
 
Mitglied seit
18.07.2001
Beiträge
2.152
Reaktionen
2
Ort
Nürnberg
bei den ganzen pointern bekommt man ja richtig lust mal wieder das gute alte c++ zu vergewaltigen
 
Mitglied seit
04.08.2002
Beiträge
1.869
Reaktionen
0
Original geschrieben von [UEP]Xyz
gehts so ?

wenn sich die frage darauf bezieht, ob der compiler das so akzeptiert, dann ja, es funktioniert so. (natürlich nur, wenn man dann auch "test2.TestCall(TestOut);" auskommentiert, weil sich die funktionsdeklaration ja geändert hat...)

jetzt kommt allerdings das große aber:
dadurch, dass du die funktion entsprechend angepasst hast, hat sie ihre gesamte generik verloren... sie kann jetzt nur noch pointer auf funktionen der klasse test1 erhalten...
 
Mitglied seit
03.08.2002
Beiträge
707
Reaktionen
0
ja, anders gehts aber nicht glaub ich. wenn o ein objekt der klasse c und op eine operation ist, dann enthaelt &o.op naemlich keine speicheradresse, sondern eine information (vielleicht igendein index in eine tabelle), um innerhalb von o auf die operation zugreifen zu koennen, d.h. es muss immer noch ein zeiger auf o mitgegeben werden, wie the_company ja schon gechrieben hat. wenn du nur ein void (*p)() hast, dann weiss keiner wie der index nun lauten soll, deswegen muss man die klasse mit angeben (void (c::*p)()). so wie du das machen willst ist meines wissens nach gar nicht erlaubt.
 
Mitglied seit
04.08.2002
Beiträge
1.869
Reaktionen
0
Original geschrieben von [UEP]Xyz
ja, anders gehts aber nicht glaub ich. wenn o ein objekt der klasse c und op eine operation ist, dann enthaelt &o.op naemlich keine speicheradresse, sondern eine information (vielleicht igendein index in eine tabelle), um innerhalb von o auf die operation zugreifen zu koennen, d.h. es muss immer noch ein zeiger auf o mitgegeben werden, wie the_company ja schon gechrieben hat. wenn du nur ein void (*p)() hast, dann weiss keiner wie der index nun lauten soll, deswegen muss man die klasse mit angeben (void (c::*p)()). so wie du das machen willst ist meines wissens nach gar nicht erlaubt.

jaja, mir ist die problematik der ganzen sache wohl schon bewusst :D
deshalb gehe ich ja gerade den umweg über die selbstgebauten wrapper.

meine frage war ja ursprünglich auch nur, ob ich da nicht vielleicht doch noch irgendwas übersehe und es den ein oder anderen trick gibt, das vielleicht noch ein wenig einfacher "hinzubiegen"....
das das, was ich machen will, nicht so einfach und ohne schmutzige tricks zu realisieren ist, dass weiß ich...

aber wie es aussieht, scheint es da wohl keine bessere lösung für die geben, als die, die ich bereits benutze!?
naja, wäre zwar schön gewesen, aber über eine wrapper-funktion gehts ja zumindest mit halbwegs überschaubarem aufwand...

gruß
m.a.k.
 
Mitglied seit
26.04.2004
Beiträge
377
Reaktionen
0
z.b. so:

Code:
class Base
{
	public:
		virtual void execFunction() = 0;
};

class TestPrint : public Base
{
	public:
		virtual void execFunction(){cout << "test" << "\n";}
};

class Counter : public Base
{
	public:
		virtual void execFunction(){static unsigned i = 0; cout << ++i << "\n";}

};

class functionCaller
{
	Base* callObject;

	public:
		void setCall(Base* object){callObject = object;}
		void execCall(){callObject->execFunction();}
};

int main()
{
	functionCaller caller;
	Base* printer = new TestPrint();
	Base* counter = new Counter();

	caller.setCall(printer);
	caller.execCall();
	caller.execCall();

	caller.setCall(counter);
	caller.execCall();
	caller.execCall();
	caller.execCall();

	delete printer;
	delete counter;

	return 0;
}

oder auch

Code:
class CTest1
{
	public:
		CTest1(){};
		~CTest1(){};

		void TestIn(){printf("Erster Test innerhalb der Klasse \n");};
};

class VeryDifferentClass
{
	public:
		void aaa(){printf("blubb \n");};
};


class CTest2
{
	public:
		CTest2(){};
		~CTest2(){};

		template<class T>
		void TestCall(T *asdf, void(T::*pfunc)(void))
		{
			(asdf->*pfunc)();
		};
};


int main()
{
	CTest1 test1;
	VeryDifferentClass test2;
	CTest2 caller;

	
	caller.TestCall(&test1, &CTest1::TestIn);
	caller.TestCall(&test2, &VeryDifferentClass::aaa);


	return 0;
}
 
Oben