Basisklasse übergeben?



  • loks hat schon Recht.

    Du musst unterscheiden zwischen dem Zeiger als Objekt an sich und dem Speicherbereich, auf den er zeigt.

    int* a = new int(4);
    int* b = a;   // beide Zeiger zeigen auf 4
    delete b;     // gibt die angeforderte Vier frei
    b = 0;        // a ist nun NICHT Null.
    

    Wenn du einen Zeiger als Value-Parameter übergibst, d.h. void modify(Test* t) , ist das eine Kopie, wie hier im Beispiel b . Änderungen am Speicherbereich dahinter sind von ausserhalb der Funktion sichtbar, Änderungen am Zeiger selbst jedoch nicht. Und zu letzteren gehört nun mal t = new Test .



  • Nexus schrieb:

    loks hat schon Recht.
    [...]

    Wenn du einen Zeiger als Value-Parameter übergibst, d.h. void modify(Test* t) , ist das eine Kopie, wie hier im Beispiel b . Änderungen am Speicherbereich dahinter sind von ausserhalb der Funktion sichtbar, Änderungen am Zeiger selbst jedoch nicht. Und zu letzteren gehört nun mal t = new Test .

    loks schrieb:

    Alle Veränderungen des Zeigers innerhalb der methode (new, delete etc) finden NUR auf diesem temporären Zeiger statt und sind daher außerhalb der Methode nicht relevant.

    Die allgemeine Formulierung ist aber irreführend.
    Es mag sein dass das delete für den Zeiger (!) außerhalb von modify() irrelevant ist. Trotzdem ist es im Allgemeinen nicht irrelevant, denn das delete verändert vllt. nicht den Zeiger, aber den Speicherbereich - Das Objekt auf welches der Zeiger zeigt wird gelöscht. Ab hier sind Zugriffe auf das Objekt undefiniert.



  • Okay, da stimme ich dir zu, seine Aussage ist in der Tat etwas missverständlich.



  • Lästermaul schrieb:

    Nexus schrieb:

    loks hat schon Recht.
    [...]

    Wenn du einen Zeiger als Value-Parameter übergibst, d.h. void modify(Test* t) , ist das eine Kopie, wie hier im Beispiel b . Änderungen am Speicherbereich dahinter sind von ausserhalb der Funktion sichtbar, Änderungen am Zeiger selbst jedoch nicht. Und zu letzteren gehört nun mal t = new Test .

    loks schrieb:

    Alle Veränderungen des Zeigers innerhalb der methode (new, delete etc) finden NUR auf diesem temporären Zeiger statt und sind daher außerhalb der Methode nicht relevant.

    Die allgemeine Formulierung ist aber irreführend.
    Es mag sein dass das delete für den Zeiger (!) außerhalb von modify() irrelevant ist. Trotzdem ist es im Allgemeinen nicht irrelevant, denn das delete verändert vllt. nicht den Zeiger, aber den Speicherbereich - Das Objekt auf welches der Zeiger zeigt wird gelöscht. Ab hier sind Zugriffe auf das Objekt undefiniert.

    ja, stimmt, das delete erzeugt hier ein Problem je nah Reihenfolge. Wenn man erst new aufruft und dann wieder delete passiert ausserhalb gar nix. Ruft man aber erst ein delete auf wie in den Beispielen hier, dann erzeugt man Probleme.



  • Also ich komme mit der Lösung von Lästermaul immer noch nicht zurecht.
    Wenn ich jetzt in der KLasse D (die unter anderem templateklasse ist)
    innerhalb der methode To_Pattern das Pattern P verändern will schreit der compiler mit:

    Fehler: invalid use of undefined type »struct Pattern«
    Fehler: forward declaration of »struct Pattern«
    

    Hier nochmal mein angepasstes Minimalbeispiel:

    //Base.h

    #ifndef BASE_H
    #define BASE_H
    
    #include <iostream>
    
    class Pattern;
    
    class Base
    {
            public:
                    virtual void To_Pattern(Pattern* P) = 0;
    };
    
    template <class T> class D : public Base
    {
            public:
                    void To_Pattern(Pattern * P)
                    {
                      std::cout << "D1:Base" << std::endl;
                      P->var = 2;
                        //std::cout<< P->var << std::endl;
                        //auf P arbeiten
                    }
    };
    
    #endif
    

    //Pattern.h

    #ifndef PATTERN_H
    #define PATTERN_H
    
    class Base;
    
    class Pattern
    {
            public:
                    Pattern() { var = -1; }
                    void foo(Base* base);
    
                     int var;
    };
    
    #endif
    

    //Pattern.cpp

    #include "Pattern.h"
    #include "Base.h"
    
    void Pattern::foo(Base* base)
    {
        base->To_Pattern(this);
    }
    

    //Main.cpp

    #include "Base.h"
    #include "Pattern.h"
    
    #include <iostream>
    
    int main(int argc, char** argv)
    {
            Base * base = 0;
            D<int> d1;
            base = &d1;
            Pattern pat;
            pat.foo(base);
            std::cout<< pat.var << std::endl;
            return 0;
    }
    


  • Weil du natürlich nicht alles so übernommen hast, sondern in Base.h direkt auf Pattern zugreifen willst, obwohl das nur ne Forward-Declaration ist.
    Am besten die Implementierung von Base in eine Base.cpp auslagern, dann "schreit" der Compiler auch nicht mehr.
    Bei mir ist der übrigens total ruhig. Nur der CPU-Lüfter dreht etwas schneller (trotzdem nicht laut) wenn ich gaaaanz viel kompilieren tu.



  • Danke Lästermaul.
    Mir ist deine Lösung schon klar aber sie deckt sich nicht mit dem was ich erreichen will (sorry für den missstand).

    Ich WILL ja Pattern verändern können in der subklasse D. Nur fehlt mir dafür die Lösung...Ich kann doch die Implementierung von Base bzw. D nicht eine cpp-datei packen weil D template-basiert ist! Oder steh ich auf dem schlauch?



  • Gafabi schrieb:

    Danke Lästermaul.
    Mir ist deine Lösung schon klar aber sie deckt sich nicht mit dem was ich erreichen will (sorry für den missstand).

    Ich WILL ja Pattern verändern können in der subklasse D. Nur fehlt mir dafür die Lösung...Ich kann doch die Implementierung von Base bzw. D nicht eine cpp-datei packen weil D template-basiert ist! Oder steh ich auf dem schlauch?

    Nein du stehst nicht auf dem Schlauch, ich dachte das ist immer noch das alte Beispiel und habs nur überflogen und das template nicht gesehen. template gabs vorher ja noch nicht 😉

    Ersetze in Base.h die Vorab-Deklaration von Pattern durch ein #include, das funktioniert in dem jetzigen Fall.
    Hoffe da kommt nicht noch mehr Komplexität dazu 🙂



  • Ich passe jetzt die Lösung von Lästermaul an weil ich absolut nicht verstehe warum eine exception in der Klasse D::To_Pattern() dann nicht mehr geworfen wird bzw. von main empfangen wird. Irgendwie hängt die this-übergabe damit zusammen weil ich mit anderen methoden innerhalb Pattern problemlos exceptions werfen kann.

    [quote="Lästermaul"]Hier einfach mal die Lösung zu deinem Problem.
    Es geht nicht einfacher bei solchen gegenseitigen Abhängigkeiten.

    Base.h

    #ifndef BASE_H
    #define BASE_H
    
    class Pattern;
    
    class Base 
    { 
        public: 
            virtual void To_Pattern(Pattern* P) = 0;
    };
    
    class D : public Base 
    { 
        public: 
            void To_Pattern(Pattern * P);
    };
    
    #endif
    

    Base.cpp

    #include <iostream>
    
    #include "Base.h"
    #include "Pattern.h"
    
    void D::To_Pattern(Pattern * P)
    {
        std::cout << "D1:Base" << std::endl; 
        // es passiert was böses und ich möchte von hier heraus
        // eine exception nach main werfen:
        if (böse) throw std::runtime_error("Es ist was böses passiert.");
        //auf P arbeiten 
    }
    

    Pattern.h

    #ifndef PATTERN_H
    #define PATTERN_H
    
    class Base;
    
    class Pattern 
    { 
        public:
            void foo(Base* base);
    }; 
    
    #endif
    

    Pattern.cpp

    #include "Pattern.h"
    #include "Base.h"
    
    void Pattern::foo(Base* base)
    { 
        base->To_Pattern(this); 
    }
    

    main.cpp

    #include "Base.h"
    #include "Pattern.h"
    
    int main(int argc, char** argv) 
    {
        Base * base = 0; 
        D d1;
        base = &d1; 
        Pattern pat; 
        try {
           pat.foo(base); 
       } catch ( std::runtime_error& ex )
       {
         // hierher wird nie gesprungen obwohl die exception eintritt
        }
    
        return 0; 
    }
    


  • Ich bräuchte schon noch Hilfe. Mein Poblem ist seltsamerweise dass der code meines letzten Posts für eine serielle Implementierung funktioniert. Hier wird also die exception bis nach oben weitergereicht. Im Falle von paralleler umgebung, also wo mehrere prozesse eine Pattern Instanz haben, bzw. jeder Prozess (CPU) eine
    eigene hat, hier keine durchreichung nach oben geschieht. Woran kann das liegen?

    Danke



  • Gafabi schrieb:

    Im Falle von paralleler umgebung, also wo mehrere prozesse eine Pattern Instanz haben, bzw. jeder Prozess (CPU) eine
    eigene hat, hier keine durchreichung nach oben geschieht. Woran kann das liegen?

    Jetzt ist es eine Multi-Prozess-Anwendung?!?
    Und wie immer: wir brauchen Code... So ohne Anhaltspunkt kann man gar nichts sagen.

    Vor allem bin ich mir nicht sicher, ob das nicht ein Spur zu hoch wird 😃 (sry...)


Anmelden zum Antworten