Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

25.2 Ein kleines Beispiel

25.2 Ein kleines Beispiel

Da ich Ihnen jetzt bestimmt schon den Mund wässrig gemacht habe, will ich jetzt zeigen, wie man Funktionszeiger baut und sie einbindet. Für diesen Zweck habe ich eine kleine Testklasse gebaut, welche nur zwei Funktionszeiger für die Demonstration besitzt, sowie zwei Methoden, welche ggf. die Funktionen, auf welche die Zeiger verweisen, aufrufen. Schauen Sie sich zunächst den Header an.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
					
#pragma once

#include <stdlib.h>

typedef void (*FAusgabe)();
typedef int (*FSumme)(int, int);

class CTest {
	private:
		FAusgabe	m_pFunc1;
		FSumme		m_pFunc2;

	public:
		// Standardkonstruktor - Initialisieren
		CTest(FAusgabe = NULL, FSumme = NULL);

		// Übergebene Funktion 1 ausführen
		void Execute1(void);

		// Übergebene Funktion 2 ausführen
		int Execute2(int iSummand1, int iSummand2);
};
					

Da die Schreibweise von Funktionszeigern etwas länger ausfallen und zudem Verwirrung stiften kann, habe ich in Zeile 5 und 6, zwei Typdefinitionen gemacht. Erstere bedeutet, dass ich mir einen Funktionszeiger mit dem Typnamen "FAusgabe" gebaut habe, welcher auf eine Funktion zeigen kann, welche weder einen Rückgabewert, noch Übergabeparameter besitzt. An diesen Zeiger können dann auch nur solche Funktionen gehangen werden. Die zweite Typendefinition bedeutet jetzt, dass ich einen Funktionszeiger, mit dem Typnamen "FSumme" definiere, welcher auf Funktionen zeigen kann, welche einen Integer zurückgeben und zwei Integer als Übergabeparameter besitzen. Wie diese Parameter im einzelnen heißen, spielt hier keinerlei Rolle.

In Zeile 10 und 11 definiere ich mir jetzt die zwei besagten Zeiger. Hier benutze ich jetzt die eben definierten Typennamen. Auffällig ist hier, dass man kein "*" benutzt. Um aber irgendwie trotzdem kenntlich zu machen, dass es sich um einen Pointer handelt, leite ich den Typnamen gerne mit einem großen "F" ein und lasse in den Variablennamen das kleine "p" einfließen. Manchmal sieht man bei dem Variablen - bzw. Attributnamen, auch den Präfix "pof", was so viel heißen soll wie "Pointer of Function".

In Zeile 15 definiere ich den Konstruktor und gebe dem Benutzer dieser Klasse die Möglichkeit, entsprechende Funktionen zu übergeben. Standardmäßig gehe ich aber davon aus, dass es keine gibt, was den Defaultwert für die Zeiger erklärt. Alternativ braucht man die Funktionen aber nicht im Destruktor mit übergeben und kann sich entsprechende Set-Methoden bauen. Dies wäre auch der übliche weg, aber das hätte das Beispiel zum einen unnötig aufgebläht und ich wollte auch mal einen anderen Weg aufzeigen.

Der Rest der Header-Datei sollte soweit klar sein und deswegen schauen wir uns nun die entsprechende CPP zu dieser Klasse an.

 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
					
// Standardkonstruktor - Initialisieren ///////////////////////////////////////
CTest::CTest(FAusgabe pFunc1, FSumme pFunc2)
	: m_pFunc1(pFunc1)
	, m_pFunc2(pFunc2)
{} // CTest ///////////////////////////////////////////////////////////////////



// Übergebene Funktion 1 ausführen ////////////////////////////////////////////
void CTest::Execute1() {
	// Wenn dem Funktionszeiger etwas zugewiesen wurde
	if (this->m_pFunc1 != NULL) {
		this->m_pFunc1();
	} // end of if
} // Execute1 /////////////////////////////////////////////////////////////////



// Übergebene Funktion 2 ausführen ////////////////////////////////////////////
int CTest::Execute2(int iSummand1, int iSummand2) {
	if (this->m_pFunc2 != NULL) {
		return this->m_pFunc2(iSummand1, iSummand2);
	} else {
		return 0;
	} // end of if
} // Execute2 /////////////////////////////////////////////////////////////////
					

In Zeile 2 bis 5 sehen Sie jetzt die Implementierung des Konstruktors. Wie man sieht, kann man Funktionszeiger ganz normal initialisieren wie andere Attribute auch.

Die Methode "Execute1", welche in den Zeilen 10 bis 15 implementiert ist, sorgt dafür, dass die erste Funktion aufgerufen wird. Dies geschieht aber nur, wenn der Funktionszeiger auf etwas verweist. Der eigentliche Aufruf der Funktion sieht nun so aus, dass man so tut, als wäre der Pointer der Funktionsname und würde zur Klasse gehören.

Die Methode "Execute2", welche in Zeile 20 bis 26 implementiert ist, sorgt jetzt dafür, dass die zweite Funktion aufgerufen wird. Das Verhalten ist wieder genauso wie in der vorhergehenden Methode. Hier wird auch wieder die Funktion aufgerufen, auf welche der Zeiger verweist und dessen Ergebnis zurück gegeben.

Schauen Sie sich nun die "main" an, in welcher ich die zwei auszuführenden Funktionen implementiert habe und mir ein Objekt der eben definierten Klasse erzeuge, welches dann meine externen Funktionen benutzen wird.

 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
					
// Einfache Ausgabefunktion ///////////////////////////////////////////////////
void MeineAusgabeFunktion() {
	printf("Hallo Welt\n");
} // MeineAusgabeFunktion /////////////////////////////////////////////////////



// Einfache Summenfunktion ////////////////////////////////////////////////////
int MeineSummenFunktion(int iSummand1, int iSummand2) {
	return iSummand1 + iSummand2;
} // MeineSummenFunktion //////////////////////////////////////////////////////



// Hauptfunktion der Anwendung ////////////////////////////////////////////////
int main(int argc, char** argv) {
	CTest oTest(&MeineAusgabeFunktion, &MeineSummenFunktion);

	oTest.Execute1();

	int iErgebnis	= oTest.Execute2(3, 4);
	printf("%i\n", iErgebnis);

	return 0;
} // main /////////////////////////////////////////////////////////////////////
					

Ausgabe:

Hallo Welt
7
		

In den Zeilen 2 bis 11 sehen Sie nun die zwei Funktionen, auf welche die Zeiger später verweisen sollen. Ich betone nochmals, dass die Funktionsköpfe genau so aussehen müssen, wie es die Definition der Funktionszeiger vorsieht.

In Zeile 17 erzeuge ich jetzt besagtes Objekt und übergebe die Adressen der beiden Funktionen, an den Konstruktor. Wichtig ist hier, dass man wirklich vor den Funktionsnamen den Adressoperator "&" schreibt, weil man sonst nichts übergeben würde, sondern die Funktionen aufruft und ggf. deren Rückgabewert übergibt.

Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012