Klassen und Zeiger



  • Hallo,

    ihr könnt mir hoffentlich bei einem kleinen Problemchen helfen.

    class KlasseA
    {
    	private:
    		typedef void (*DefFunctionA)();
    
    		void FunctionB(){
    			if(FunctionA)
    				FunctionA();
    		}
    	public:
    		KlasseA(){
    			FunctionA=NULL;
    		}
    
    		DefFunctionA FunctionA;
    
    };
    
    class KlasseB
    {
    	private:
    		KlasseA *Test1;
    
    	public:
    		KlasseB(){
    			Test1 = new KlasseA();
    			Test1->FunctionA=&KlasseB::Funktion();  //<---  das gibt fehler
    		}
    
    		Funktion(){
    			//----
    		}
    };
    

    Das ist zwar kein sehr schönes Beispiel aber entsprecht dem was ich benötige. Es gibt Kompiler die das so akzeptieren, aber mein jetziger tut das nicht.

    Fehlermeldung:
    ISO C++ forbids taking the adress of an unqualified or parenthesized non-static member function to a form pointer to a member function.

    ich möchte die Memberfunktion aber ungern statisch machen.



  • Du hast 2 Probleme. Erstens ist die Syntax falsch (die runden Klammern gehoeren weg), zweitens ist dein Funktionstyp falsch (du brauchst einen Memberfuntkionszeiger).





  • Danke für die Antwort,

    @Kellerautomat: mit den Klammern ist nur ein Tippfehler gewesen...

    ich denk bind ist der richtige Ansatz. Ich habe mir verschiedene Beispiele angeguckt, bekomme das aber irgendwie nicht auf das Beispiel angewendet. Ich habe es auch mit boost::bind versucht und bin gescheitert 😞

    wäre jemand so nett und könnte das mal in C++ Code umsetzten?



  • Frageman123 schrieb:

    ich denk bind ist der richtige Ansatz. Ich habe mir verschiedene Beispiele angeguckt, bekomme das aber irgendwie nicht auf das Beispiel angewendet. Ich habe es auch mit boost::bind versucht und bin gescheitert 😞

    Zeig mal deinen Versuch!



  • Das Problem ist, dass KlasseA::DefFunctionA und KlasseB::Funktion verschiedene Signaturen haben. KlasseA::DefFunctionA nimmt kein Argument während KlasseB::Funktion ein Objekt vom Typ KlasseB* als impliziten Parameter benötigt.

    class KlasseB;
    
    class KlasseA
    {
    private:
    	//typedef void(KlasseB::*DefFunctionA)();
    	using DefFunctionA = void(KlasseB::*)();
    
    	void FunctionB(KlasseB &b){ //du brauchst ein Object von Typ KlasseB um KlasseB::Funktion / DefFunctionA aufrufen zu können
    		if (FunctionA)
    			(b.*FunctionA)();
    	}
    public:
    	KlasseA(){
    		FunctionA = nullptr; //NULL ist doof
    	}
    
    	DefFunctionA FunctionA;
    
    };
    
    class KlasseB
    {
    private:
    	unique_ptr<KlasseA> Test1;
    
    public:
    	KlasseB(){
    		Test1 = make_unique<KlasseA>();
    		Test1->FunctionA = &KlasseB::Funktion;
    	}
    
    	void Funktion(){ //void vergessen
    		//----
    	}
    };
    

    Mit bind würde ich nicht rummachen. Das ist kompliziert und unnötig. Nimm Lambdas / std::function.

    class KlasseA
    {
    private:
    	void FunctionB(){
    		if (FunctionA)
    			FunctionA();
    	}
    public:
    	KlasseA() : FunctionA(nullptr){ //initializer list, ist manchmal besser, nie schlechter, sollte man immer benutzen
    	}
    	std::function<void()> FunctionA; //seltsame typedefs entfallen komplett
    };
    
    class KlasseB
    {
    private:
    	KlasseA Test1;
    
    public:
    	KlasseB(){
    		Test1.FunctionA = [this]{ this->Funktion(); }; //hier haben wir den KlasseB-Pointer,
    			//der für den Aufruf von KlasseB::Funktion nötig ist gleich mitgegeben
    	}
    
    	void Funktion(){
    		//----
    	}
    };
    

  • Mod

    wäre jemand so nett und könnte das mal in C++ Code umsetzten?

    Das wäre so ganz grobes C++:

    #include <functional> // function, bind
    
    class KlasseA
    {
    	std::function<void()> FunctionA;
    
    public:
    	template <typename Callable>
    	KlasseA( Callable c ) :
    		FunctionA(c)
    	{}
    
    	void FunctionB()
    	{
    		if (FunctionA)
    			FunctionA();
    	}
    };
    
    #include <memory> // unique_ptr
    #include <iostream> // cout
    
    class KlasseB
    {
    	std::unique_ptr<KlasseA> Test1;
    
    public:
    	KlasseB() :
    		Test1( new KlasseA( std::bind(&KlasseB::Funktion, this) ) )
    	{}
    
    	void Funktion()
    	{
    		std::cout << "Deutschland vs Brasilien: 2:2 + Elfmeterschießen, Deutschland gewinnt\n";
    	}
    
    	void FunktionVonA()
    	{
    		Test1->FunctionB();
    	}
    };
    
    int main()
    {
    	KlasseB b;
    	b.FunktionVonA();
    }
    

    Merke aber: Ein Memberfunktionszeiger wäre hier deutlich effizienter!

    Das ist kompliziert und unnötig.

    Überhaupt nicht! Siehe oben. Der einzige Vorteil von Lambdas besteht darin dass sie lesbarer sind und weniger Speicher erfordern.



  • Wie so oft führen viele Wege nach Rom 🙂

    Vielen Dank für eure Zahlreichen Möglichkeiten.

    @nwp3:
    deine erste Möglichkeit geht davon aus das die Methode die KlasseA übergeben wird immer von KlasseB kommt. Das bringt mir leider nur bedingt etwas.

    wie sieht es denn damit aus? Das lässt sich kompilieren und funktioniert auch, zumindest mit dem QT Compiler. Andere Compiler machen das nicht mit 😕

    Test1->FunctionA = reinterpret_cast<DefFunctionA>(&KlasseB::Funktion);
    

    Den Typdef für DefFunctionA natürlich global setzten.



  • Frageman123 schrieb:

    wie sieht es denn damit aus? Das lässt sich kompilieren und funktioniert auch, zumindest mit dem QT Compiler. Andere Compiler machen das nicht mit 😕

    Test1->FunctionA = reinterpret_cast<DefFunctionA>(&KlasseB::Funktion);
    

    Sieht nicht gut aus. Du sagst "Die Funktion KlasseB::Funktion braucht ein Zeiger auf ein KlasseB-Objekt, tu so als bräuchte sie ihn nicht".
    Wenn du mittelmäßig Glück hast stürzt das Programm beim Aufruf ab, weil die falsche Calling Convention benutzt wird.
    Wenn du Pech hast sieht es so aus als würde es funktionieren und macht dir irgendwas kaputt was du jahrelang nicht findest.
    Wenn du richtig doll viel Glück hast läuft es, KlasseB::Funktion wird aufgerufen, aber der this-Zeiger ist nochimmer falsch / nicht existent. Wenn du darauf zugreifst, eventuell implizit, dann stürzt es ab. Wenn du ihn nicht benötigst kannst du einfach static davor schreiben.

    TLDR: Kann so nicht funktionieren.

    Ich meine der Schlüssel zur Lösung ist die Frage, ob für den Aufruf von DefFunctionA ein Objekt nötig sein soll und wenn ja welche.



  • Danke,

    solche Fehler sind extrem mies.

    Ich steh nur mittlerweile komplett auf dem Schlauch. Ist das so exotisch was umsetzen will? Oder habe ich das nur falsch erklärt? Hab bisher mit dem BCB Compiler gearbeitet und da baut meine ganze Klassenstruktur drauf auf, das ich Funktionen an andere Klassen übergeben kann. Der Compiler benötigt nur das Schlüsselwort "closure" und muss von der Stammklasse abgeleitet sein.

    typedef void __fastcall (__closure*DefFunctionA)();
    

    Gibt es das nicht auch für andere Compiler? bzw. das sollte man doch bestimmt auch "nachbauen" können.



  • Frageman123 schrieb:

    Gibt es das nicht auch für andere Compiler?

    Nein, nicht standardkonform.

    bzw. das sollte man doch bestimmt auch "nachbauen" können.

    Ja, siehe Arcoth.


Anmelden zum Antworten