Array von Funktionen



  • chrische5 schrieb:

    ... und es wäre hilfreich, weil übersichtlich, wenn ich viele Funktionen so zusammenfassen könnte und dann nur noch einen Parameter ...

    Das wäre überhaupt nicht übersichtlich!

    Aha, Du will in der Tat Funktionen in ein Array schreiben und die Funktion über den Laufparameter des Arrays ansprechen. Ich glaube da nicht daran, dass das funktionieren wird/kann.



  • Nein. Das ist kein Problem. Ich habe eine Funktion an die ich eine Parameter übergeb. Mit diesem mache ich dann diverse Berechnungen und am Ende würde ich gerne eine Funktion in Abhängigkeit von diesem Parameter aufrufen. Ich konnte also eine switch-Anweisung machen und alle möglichen Zustände vom Parameter überprüfen, da es aber 13 sein können finde ich das nicht sehr attraktiv. Also dachte ich mir, dass ich ja eine Funktionsarray aufrufe könnte, in dem ich den Parameter im Namen angebe. Also genauso, wie ich ein normales array benutze. Ich wollte nur wissen, ob so was möglich ist und wenn wie.

    chrische



  • Meinst du vielleicht sowas ?

    typedef float (*myfunc)( int param1, int param2 );
    
    float testfunc1( int param1, int param2 )
    {
    	return 1.0;
    }
    
    float testfunc2( int param1, int param2 )
    {
    	return 2.0;
    }
    
    float testfunc3( int param1, int param2 )
    {
    	return 3.0;
    }
    
    myfunc	array_of_functions[3] = { testfunc1, testfunc2, testfunc3 };
    
    int main(int argc, char* argv[])
    {
    	for ( int i=0; i<3; i++ )
    	{
    		float result = array_of_functions[i]( 0,0 );
    		printf( "%f", result );
    	}
    
    	return 0;
    }
    


  • Hallo

    Das schaut sehr gut aus. Ich werde es mal probieren und mich bei eventuellen Probelem wieder melden. Vielen Dank für Eure schnelle Hilfe.

    chrische



  • Hallo

    chrische5 schrieb:

    ... und es wäre hilfreich, weil übersichtlich, wenn ich viele Funktionen so zusammenfassen könnte und dann nur noch einen Parameter ...

    Das wäre überhaupt nicht übersichtlich!

    Ob es übersichtlich ist oder nicht sollte doch nun wirklich derjenige entscheiden, der sein Programm kennt.

    Ich habe es leider nicht richtig hinbekommen. Ich arbeite an einer Dialogfeldbasierten Anwendung und habe versucht in der *.cpp Datei meiner eigenen CCheckBedingung-Klasse alles zu zu schreiben, wie es vorgeschlagen wurde:

    typedef int(*myFunctions) (CWuerfel arWuerfel[]);
    

    Das ganz oben und dann die Funktionen. Am Ende steht:

    myFunctions aCheckFunctions[13]={CCheckBedingung::CheckEinsen,CCheckBedingung::CheckZweien,CCheckBedingung::CheckDreien,CCheckBedingung::CheckVieren,CCheckBedingung::CheckFuenfen,CCheckBedingung::CheckSechsen,CCheckBedingung::CheckDreierPasch,CCheckBedingung::CheckViererPasch,CCheckBedingung::CheckFullHouse,CCheckBedingung::CheckKleineStrasse,CCheckBedingung::CheckGrosseStrasse,CCheckBedingung::CheckChance,CCheckBedingung::CheckKniffel};
    

    Ist leider etwas lang geworden, aber es sind nun mal 13 Funktionen.

    Nun bekomme ich folgende Fehlermeldungen(es sind genau 13):

    d:\Visual Studio Projekte\Kniffel\CheckBedingung.cpp(293): error C2440: 'initializing' : cannot convert from 'int (__thiscall CCheckBedingung::* )(CWuerfel [])' to 'myFunctions'

    Wo liegt mein Fehler? Muss ich noch in der *.h -Datei rumschreiben?

    chrische



  • Klingt mir eher nach einem Fehler im Design *grumpf* 😉

    Poste doch mal die Funktionsrümpfe deiner einzelnen Check-Funktionen, dann wird sich schon eine Möglichkeit zeigen, das alles etwas eleganter zu lösen.



  • Hallo

    Ich weiss leider nicht genau, was der Funktionsrumpf ist, baer ich poste mal das hier:

    int CCheckBedingung::CheckEinsen(CWuerfel arWuerfel[])
    {
    	//int Variable für die Gesamtpunktzahl 
    	int iSummeEinsen=0;
    	//Schleife für alle fünf Würfel
    	for(int i=0;i<5;i++)
    		//wenn Würfelzustand =1 oder Würfelzustand =7 (1, aber gesetzt) wird Summe um eins erhöht
    		if((arWuerfel[i].m_iCheckZustand==1) || (arWuerfel[i].m_iCheckZustand==7))
    			iSummeEinsen+=1;
    	//Summe wird zurückgegeben
    	return iSummeEinsen;
    }
    

    Natürlich ist das nicht bei jeder Funktion genau dasselbe.

    chrische



  • Und dein Ziel ist, die Punkte eines einzelnen Wurfes zu ermitteln oder verfolgst du noch weitere Ziele?



  • Hallo

    Mein Ziel ist es, dass wenn jemand dreimal gewürfelt hat und sich dann entschieden hat, welches Feld er belgen möchte (eonsen, DreierPasch, Kniffel, Kleine Strasse,...) die dazugehörige Funktion aufgerufen wird. Ich würde also gerne einer Funktion einen int-Parameter übergeben, in dem steht, welches Feld geklickt wurde und dann die Funktion aufrufen. Da wäre es natürlich praktisch keine switch-Anweisung zu schreiben, sondern nur den Funktionsnamen und den Parameter anzugeben.

    chrische



  • Dieser Thread wurde von Moderator/in Unix-Tom aus dem Forum MFC (Visual C++) in das Forum C++ verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Ist leider etwas lang geworden, aber es sind nun mal 13 Funktionen.

    Nun bekomme ich folgende Fehlermeldungen(es sind genau 13):

    d:\Visual Studio Projekte\Kniffel\CheckBedingung.cpp(293): error C2440: 'initializing' : cannot convert from 'int (__thiscall CCheckBedingung::* )(CWuerfel [])' to 'myFunctions'

    Die Compilermeldung kommt daher, dass deine Methoden einen this-Pointer benötigen, der bei dieser Art des Funktionsaufrufes nicht zur Verfügung steht.

    Wenn deine Methoden in der Klasse CCheckBedingung keinen Zugriff auf Variablen der Klasse benötigen, kannst du diese ja auch static deklarieren.

    Dann funktionierts auch mit dem Funktionspointerarray.

    typedef int (*FUNCTIONPOINTER)(CWuerfel*);
    
    class MyClass
    {
    public:
    	MyClass();
    
    	static int testfunc1(CWuerfel*) { return 1; }
    	static int testfunc2(CWuerfel*) { return 2; }
    	static int testfunc3(CWuerfel*) { return 3; }
    };
    
    FUNCTIONPOINTER funcpointerarray[3] = { MyClass::testfunc1, MyClass::testfunc2, MyClass::testfunc3 };
    


  • Hallo

    Ich habe das jetzt mal probiert, obwohl ich ehrlich gesagt nicht genau weiss, was es bedeutet einen Funktion als static zu deklarieren (vielleicht kannst du mir da mal auf die Sprünge helfen) Mein code schaut jetzt folgendermaßen aus:

    #pragma once
    #include "Wuerfel.h"
    
    typedef int(*myFunctions) (CWuerfel arWuerfel[]);
    
    class CCheckBedingung
    {
    public:
    	CCheckBedingung(void);
    	~CCheckBedingung(void);
    	// Checkt, ob 1en schon belegt wurden
    	static void Sortieren(CWuerfel arWuerfel[]);
    	//macht aus doppelten Augenzahlen eine Null
    	static void DoppelteLoeschen(CWuerfel arWuerfel[]);
    	// Checkt, wieviel Punkte man bekommt, wenn man auf Einsen klickt
    
    	static int CheckEinsen(CWuerfel arWuerfel[]);
    	// Checkt, wieviel Punkte man bekommt, wenn man auf Zweien klickt
    	static int CheckZweien(CWuerfel arWuerfel[]);
    	// Checkt, wieviel Punkte man bekommt, wenn man auf Dreien klickt
    	static int CheckDreien(CWuerfel arWuerfel[]);
    	// Checkt, wieviel Punkte man bekommt, wenn man auf Vieren klickt
    	static int CheckVieren(CWuerfel arWuerfel[]);
    	// Checkt, weiviel Punkte man bekommt, wenn man auf Fünfen klickt
    	static int CheckFuenfen(CWuerfel arWuerfel[]);
    	// Checkt, weiviel Punkte man bekommt, wenn man auf Sechsen klickt
    	static int CheckSechsen(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkte man bekommt, wenn man auf DreierPasch klickt
    	static int CheckDreierPasch(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkte man bekommt, wenn man auf ViererPasch klickt
    	static int CheckViererPasch(CWuerfel arWuerfel[]);
    	//Checkt wieviel Punkte man bekommt, wenn man auf Full House klickt
    	static int CheckFullHouse(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkte man bekommt, wenn man auf Kleine Strasse klickt
    	static int CheckKleineStrasse(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkt man bekommt, wenn man auf grosse Strasse klickt
    	static int CheckGrosseStrasse(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkte man bekommt, wenn man auf Kniffel drückt 
    	static int CheckKniffel(CWuerfel arWuerfel[]);
    	//Checkt, wieviel Punkte man bekommt, wenn man auf Chance klickt
    	static int CheckChance(CWuerfel arWuerfel[]);
    
    	bool m_abIsChecked[13];
    
    };
    
    myFunctions aCheckFunctions[13]={CCheckBedingung::CheckEinsen,CCheckBedingung::CheckZweien,CCheckBedingung::CheckDreien,CCheckBedingung::CheckVieren,CCheckBedingung::CheckFuenfen,CCheckBedingung::CheckSechsen,CCheckBedingung::CheckDreierPasch,CCheckBedingung::CheckViererPasch,CCheckBedingung::CheckFullHouse,CCheckBedingung::CheckKleineStrasse,CCheckBedingung::CheckGrosseStrasse,CCheckBedingung::CheckChance,CCheckBedingung::CheckKniffel};
    

    Leider bekomm ich jetzt eine neue Fehlermeldung aus der ich ebenfalls nicht schlau werde:

    Kniffel error LNK2005: "int (__cdecl** aCheckFunctions)(class CWuerfel * const)" (?aCheckFunctions@@3PAP6AHQAVCWuerfel@@@ZA) already defined in CheckBedingung.obj

    gefolgt von:

    Kniffel fatal error LNK1169: one or more multiply defined symbols found

    Vieleicht wisst ihr ja, was er will.

    chrische



  • Kniffel error LNK2005: "int (__cdecl** aCheckFunctions)(class CWuerfel * const)" (?aCheckFunctions@@3PAP6AHQAVCWuerfel@@@ZA) already defined in CheckBedingung.obj

    Liegt daran, dass du das Array in der Headerdatei definierst.

    Jedesmal wenn du dann die Datei CheckBedingung.h in eine cpp includierst wird ein neues Array vom Compiler mit gleichem Namen angelegt. Das mag der Linker gar nicht, da er ja nicht weiss welches Objekt nun unter dem Namen angesprochen wird => Fehler ... already defined in ...

    Lösung:

    Pack die Zeile

    myFunctions aCheckFunctions[13]={CCheckBedingung::Check...};
    

    in die cpp-Datei CheckBedingung.cpp.

    Falls du aus anderen Files auch auf das Array zugreifen musst, deklariere das Array als extern im Headerfile CheckBedingung.h:

    extern myFunctions aCheckFunctions[];
    

    Ich hoffe das hilft.



  • man kann für headerdateien auch die Übliche Vorgehensweise wählen und sie nur bedingt kompilieren, wenn sie noch nicht kompiliert worden sind:

    #ifndef MYHEADER_H
    #define MYHEADER_H
    
    //dieser Teil wird vom Compiler nur einmal gelesen, 
    //beim zweiten mal ist MYHEADER_H bereits definiert und
    //der Präprozessor entfernt den Code vorm kompilieren
    //natürlich sollte das definierte Symbol immer unterschiedlich sein
    
    #endif
    

    Damit werden mehrfache definitionen durch mehrfache Einbindung von Headern unmöglich.



  • @pumuckl: Includeguards helfen in diesem fall nicht.

    Damit werden mehrfache definitionen durch mehrfache Einbindung von Headern unmöglich.

    sollte eigentlich heissen :
    Damit werden mehrfache definitionen durch mehrfache Einbindung von Headern in einer kompilationseinheit (sagt man das so ?) unmöglich.
    Das problem hier ist aber das der gleiche Header in verschiedenen kompilationseinheiten eingebunden wird, daher befindet sich die variable dann in mehreren .obj-files und das mag der linker nicht.
    Wie tvdog schon gesagt hat extern ist die lösung.
    BTW Includeguards verhindern compilerfehler, extern verhindert linkerfehler.
    Kurt



  • Hallo

    Ich habe die typedef-Anweisung und die Array Deklaration in die *.h-Datei geschrieben und in der *.cpp-Datei steht der Rest:

    *h-Datei:

    typedef int(*myFunctions) (CWuerfel arWuerfel[]);
    myFunctions aCheckFunctions[13];
    

    *.cpp-Datei:

    myFunctions aCheckFunctions[13]={CCheckBedingung::CheckEinsen,CCheckBedingung::CheckZweien,CCheckBedingung::CheckDreien,CCheckBedingung::CheckVieren,CCheckBedingung::CheckFuenfen,CCheckBedingung::CheckSechsen,CCheckBedingung::CheckDreierPasch,CCheckBedingung::CheckViererPasch,CCheckBedingung::CheckFullHouse,CCheckBedingung::CheckKleineStrasse,CCheckBedingung::CheckGrosseStrasse,CCheckBedingung::CheckChance,CCheckBedingung::CheckKniffel};
    

    In meiner Funktion rufe ich jetzt mit einen Feldparameter die gewünschte Funktion auf und bekomme dabei leider immer eine Fehlermeldung. Hier erstmal der Aufruf der Funktion:

    int CKniffelDlg::DoClicked(int Feld)
    {
    	//wenn Einsen bereits belegt sind, erscheint MessageBox mit Meldung
    	if(m_cCheckBedingung.m_abIsChecked[Feld])
    		MessageBox("Sie haben dieses Feld bereits belegt");
    	//ansonsten werden die Punkte ausgegeben, Belegt-Varible auf true gesetzt und alle Würfel neu gewürfelt 
    	else
    	{
    		//Aufruf der Funktion CheckEinsen aus der Klasse CCheckBedingung, in der ermittelt wird, wie hoch die
    		//Punktzahl beim Einserfeld ist und Zuweisung zur Variablen von IDC_STATICAUSGABEEINSEN
    		m_aiAusgabe[Feld]=m_cCheckBedingung.aCheckFunctions[Feld](arWuerfel);
    

    Das ist nicht die ganze Funktion, aber der wichtige Aufruf steht in der letzten Zeile. Wenn ich nun auf einen Button klicke und die Funktion DoClicked aufgerufen wird, bekomme ich die Fehlermeldung:

    Unhandled exception at 0xcccccccc in Kniffel.exe: 0xC0000005: Access violation reading location 0xcccccccc.

    Vielleicht wisst Ihr ja Hilfe, da Ihr bis jetzt ja immer Bescheid wusstet.

    chrische



  • Hallo

    Weiss keiner, was hier los sein könnte?

    chrische



  • Vielleicht ist Feld kein gültiger Index für aCheckFunctions.

    BTW: Das mit den static-Funktionen solltest du wieder rückgängig machen und stattdessen einen Funktionspointer auf ein Klassenelement benutzen.



  • Hallo

    "Feld" ist ein gültiger Index, da ich 0 übergebe und das Array 13 Plätze hat (von 0-12) Warum ist das mit static ungünstig? Ich habe wie gesagt noch gar nicht richtig verstanden, was static eigentlich bringt.

    chrische



  • Eine statische Methode hat keinen this-Pointer, d.h. alle Instanzen der Klassen teilen sich die Methode.


Anmelden zum Antworten