Zuständigkeitsketten/vererbungsproblem



  • ok, vielen dank erst einmal für die konstruktive Kritik 😃

    asc schrieb:

    Nein! Pure virtuelle Methoden ergeben keinen Fehler. Zumindestens wenn man die Regeln der Polymorphie unter C++ richtig anwendet, und die Klasse als abstrakte Basisklasse dienen soll. Hier hättest du imho schon ein wenig nachforschen müssen, warum es in deinem Programm zu Fehlern kommt.

    Ja da hast du recht, ich hatte wahrscheinlich eine Fehlermeldung fals gedeutet, danke dafür.

    asc schrieb:

    Ähmm... std::list<obj*> funktioniert sicherlich, und es ist eher fraglich warum du die Liste als Zeiger halten willst.

    Du hast recht in einem vorherigen vcersuch schrieb ich ausversehen std::list<*obj> , jetzt gehts 🙂

    asc schrieb:

    Davon abgesehen hält man in der Regel aus guten Gründen keine Iteratoren langfristig. Dies man zwar in einer Liste meist noch gehen, aber ich hoffe du weist das Iteratoren je nach Container zwischenzeitlich ungültig werden können...

    ok, danke für den hinweis, das hab ich noch nicht gewusst 🙂

    Ich hab einmal versucht alles so zu übernehmen, eine Fehlermeldung bekomme ich noch immer

    #include <iostream>
    #include <list>
    #include <string>
    
    class obj
    {
    	public:
    		obj() {}
    		virtual ~obj() {}
    		virtual std::string query( std::string& ) = 0;
    		virtual std::string getQuery() = 0;
    	protected:
    		std::string res_return;
    };
    
    class A : public obj
    {
    	public:
    		A() : i(0) {}
    		int i;
    		std::string query( std::string& q )
    		{
    			res_return = "Klasse A";
    			return res_return;
    		}
    		std::string getQuery() { return res_return; }
    };
    
    class B : public obj
    {
    	public:
    		B() : j(0) {}
    		int j;
    		std::string query( std::string& q )
    		{
    			res_return = "Klasse B";
    			return res_return;
    		}
    		std::string getQuery() { return res_return; }
    };
    
    class ChainOfResponsibility
    {
    	public:
    		ChainOfResponsibility( obj*, obj* );
    		~ChainOfResponsibility() {}
    		bool request( std::string& );
    	private:
    		std::list<obj*> chain;
    };
    
    ChainOfResponsibility::ChainOfResponsibility( obj* ObjA, obj* ObjB)
    {
    	chain.push_back( ObjA );
    	chain.push_back( ObjB );
    }
    
    bool ChainOfResponsibility::request( std::string& test )
    {
    	std::list<obj*>::iterator iter;
    	for( iter = chain.begin(); iter != chain.end(); iter++ )
    	{
    		iter.query( "bla" );
    		if( iter.getQuery() == test ) return true;
    	}
    	return false;
    }
    
    int main()
    {
    	A *a;
    	B *b;
    	ChainOfResponsibility Ch( a, b );
    	std::string r( "Klasse b" );
    	if( Ch.request( r ) )
    		std::cout << "Klasse B wurde gefunden" << std::endl;
    	else std::cout << "Klasse B konnte nicht gefunden werden" << std::endl;
    }
    

    Fehler:

    g++ TESTAPP.cpp -o TESTAPP
    TESTAPP.cpp: In member function ‘bool ChainOfResponsibility::request(std::string&)’:
    TESTAPP.cpp:63: error: ‘struct std::_List_iterator<obj*>’ has no member named ‘query’
    TESTAPP.cpp:64: error: ‘struct std::_List_iterator<obj*>’ has no member named ‘getQuery’
    

    hier ist also der fehler, oder?:

    iter.query( "bla" );
    		if( iter.getQuery() == test ) return true;
    

    ich habs mal so prtobiert, brachte aber nichts:

    iter.*query( "bla" );
    		if( iter.*getQuery() == test ) return true;
    

    wie kann ich per iterator auf die query Funktion zugreifen?
    mfg



  • Habe jetzt nicht alles gelesen, aber Iteratoren unterstzützen normalerweise den *-Operator:

    (*iter).query
    


  • drakon schrieb:

    Habe jetzt nicht alles gelesen, aber Iteratoren unterstzützen normalerweise den *-Operator:

    (*iter).query
    

    wie waere es mit

    iter->query
    

    ?



  • Shade Of Mine schrieb:

    drakon schrieb:

    Habe jetzt nicht alles gelesen, aber Iteratoren unterstzützen normalerweise den *-Operator:

    (*iter).query
    

    wie waere es mit

    iter->query
    

    ?

    Jo, wollte ich auch noch schreiben, musste aber gerade weg. 😉



  • Shade Of Mine schrieb:

    wie waere es mit

    iter->query
    

    ?

    habs versucht:

    bool ChainOfResponsibility::request( std::string& test )
    {
    	std::list<obj*>::iterator iter;
    	for( iter = chain.begin(); iter != chain.end(); iter++ )
    	{
    		iter->query( "bla" );
    		if( iter->getQuery() == test ) return true;
    	}
    	return false;
    }
    

    Fehler:

    g++ TESTAPP.cpp -o TESTAPP
    TESTAPP.cpp: In member function ‘bool ChainOfResponsibility::request(std::string&)’:
    TESTAPP.cpp:63: error: request for member ‘query’ in ‘* iter.std::_List_iterator<_Tp>::operator-> [with _Tp = obj*]()’, which is of non-class type ‘obj*’
    TESTAPP.cpp:64: error: request for member ‘getQuery’ in ‘* iter.std::_List_iterator<_Tp>::operator-> [with _Tp = obj*]()’, which is of non-class type ‘obj*’
    

    mfg



  • iter zeigt ja selbst auf einen Zeiger. Du musst den Iterator also zweimal dereferenzieren:

    (*iter)->query
    

    oder:

    (**iter).query
    


  • Auma schrieb:

    ...habs versucht:

    ...
    {
    	std::list<obj*>::iterator iter;
    ...
    

    Naja, kleiner Denkfehler von Dir:

    • ein Iterator zeigt auf ein Listenelement. Deswegen kann man mit '->' bzw. '*' auf ein Listenelement zugreifen.
    • in Deiner Liste verwaltest Du aber Zeiger auf Objekte. Willst Du also von einem Listenelement auf das dahinterliegende Objekt zugreifen, brauchst Du wiederum '->' bzw. '*'

    Ein Hinwis darauf findet sich tatsächlich in der Fehlermeldung:

    Auma schrieb:

    ...

    ...List_iterator<_Tp>::operator-> [with _Tp = obj*]()’, which is of non-class type ‘obj*’...
    

    ...

    Hier brauchst Du also:

    (*iter)->query
    // iter = "Zeiger auf ein Listenelement"
    // (*iter) = Listenelement = obj*
    // (*iter)-> = obj
    

    Gruß,

    Simon2.



  • ja 😃 vielen dank jetzt Kompiliert es... leider kommt es zu einem Segmentation fault 😮
    Ich lass das ganze mal durch nen Debugger laufen 🙂 ...
    mfg



  • Auma schrieb:

    Ich lass das ganze mal durch nen Debugger laufen 🙂 ...
    mfg

    👍

    Gute Entscheidung.



  • Auma schrieb:

    ja 😃 vielen dank jetzt Kompiliert es... leider kommt es zu einem Segmentation fault 😮
    Ich lass das ganze mal durch nen Debugger laufen 🙂 ...
    mfg

    Dir ist hoffentlich der Fehler an dieser Stelle klar:

    ChainOfResponsibility::ChainOfResponsibility( obj* ObjA, obj* ObjB)
    {
        chain.push_back( ObjA );
        chain.push_back( ObjB );
    }
    
    int main()
    {
        A *a; // 1.
        B *b; // 1.
        ChainOfResponsibility Ch( a, b ); // 2.
        //...
    }
    

    Ansonsten: Zurück zu den Grundlagen...

    1. Uninitialisierte Zeiger sind böse
    2. Du kannst doch nicht erwarten das eben diese Zeiger in deiner Liste Sinn machen.

    Davon ganz abgesehen solltest du Tips immer ganz oder garnicht beherzigen:

    virtual std::string query( std::string& ) = 0;
    

    Soll query den Übergabestring ändern können? Wenn nein, bitte eine konstante Referenz verwenden (Schreibweise: "std::string const &" oder "const std::string &").

    Zudem trennt man Code in Deklaration und Definition (Header/Source) und es ist - ich wiederhole nochmal - eine Unsitte im Header die Bezeichner wegzulassen. Stell dir vor du schaust dir deinen Code nach einen halben Jahr nochmal an. Möchtest du für einen Kurzen Überblick wirklich genötigt werden die Implementierung durchzuarbeiten? Man sollte immer gegen die Schnittstelle (Header), nicht gegen die Implementierung programmieren, und daher sollte für das Verständnis der Header ausschlaggebend sein.

    class ChainOfResponsibility
    {
        //...
        bool request( std::string& );
        //...
    }
    

    Was soll diese Methode uns sagen? Ich kann daraus nur ablesen das irgendetwas angefordert wird. Der Bezeichner (da fehlend) gibt nichts her, und auch der Methodenname alleine hilft nicht dabei den Aufruf zu verstehen. Was ich noch ablesen kann ist, das die Methode einen String als Argument erhält, und dieser innerhalb der Methode manipuliert wird (Ansonsten würde ja eine konstante Referenz verwendet werden).

    Programme sollten so geschrieben werden das sie möglichst selbsterklärend sind. Wenn du deinen Code nach einen halben Jahr nochmal üerfliegst weißt du wovon ich spreche...

    cu André



  • ja, danke es funktioniert.

    asc schrieb:

    Uninitialisierte Zeiger sind böse

    keine Ahnung warum ich das übersehen hab 🙄

    asc schrieb:

    [...]bitte eine konstante Referenz verwenden[...]

    das Programm schrieb ich ja nur um das Prinzip besser zu verstehen, aber du hast recht wenn dann richtig 🙂
    Die Bezeichner spielen somit auch keine Rolle, ich werde das Programm/den Code sicher nicht lange aufbewahren.
    mfg



  • Auma schrieb:

    asc schrieb:

    [...]bitte eine konstante Referenz verwenden[...]

    das Programm schrieb ich ja nur um das Prinzip besser zu verstehen, aber du hast recht wenn dann richtig 🙂
    Die Bezeichner spielen somit auch keine Rolle, ich werde das Programm/den Code sicher nicht lange aufbewahren.

    Der Mensch ist ein Gewohnheitstier. Wenn du dir den Stil früh angewöhnst, wird du ihn auch durchziehen wenn du es wirklich benötigst. Zudem mag das Projekt ein "Wegwerfprojekt" sein, für die anderen Threadleser helfen Bezeichner aber durchaus weiter, selbst wenn du diese nicht benötigst ;)...

    cu André


Anmelden zum Antworten