bidirektionale Referenz



  • Moin!
    Ich habe bisher eher mit Java gearbeitet, deswegen komme ich mit den Eigenarten von C++ noch nicht so ganz zurecht.

    Mein Problem:
    Ich habe eine Klasse Logic, aus der heraus eine Instanz der Klasse SortAlgo erzeugt werden soll. Als Parameter wiederum soll der Konstruktor von SortAlgo die Instanz der Klasse Logic bekommen, weil die Logic bei Rückmeldung von SortAlgo etwas zeichnen soll.

    Ich habe jetzt folgendes:

    1 class SortAlgo;
    
    2 class Logic {
    3 public:
    4   Sortalgo algo;
    
    5   void startSortAlgo();
    6   void zeichne(param);
    7 };
    
    void Logic::startSortAlgo(){
       algo.sort;
    }
    

    und in einer anderen Header-Datei:

    1 class Logic;
    
    2 class SortAlgo {
    3 public:
    4   Logic l;
    
    5   void sort();
    6   void callLogic(param);
    7 };
    
    void SortAlgo::callLogic(param){
       l.zeichne(param);
    }
    

    Jetzt habe ich folgenden Compiler-Fehler: "logic.hpp:4: error: field `algo' has incomplete type"
    Ich habe schon ein bißchen bei google und hier im Forum gesucht, aber noch nicht wirklich DIE Lösung gefunden. Denn wenn ich das Ganze als Referenz deklariere, kann ich ja z. B. nicht mehr auf algo.sort() zugreifen. Und wie übergebe ich meine Logik-Instanz dem Konstruktor von SortAlgo?

    Ich hoffe, das war einigermaßen verständlich...

    Gruß, Tigger



  • Sorry, der Beitrag war von mir...



  • Du kannst zwei Klassen nicht gegenseitig ineinander einbinden - schon weil deine Konstruktion ein unendlich großes Objekt erzeugen würde (ein SortAlgo in einem Logic in einem SortAlgo in einem ...). Was du brauchst, sind Referenzen oder Pointer:

    class Logic;
    
    class SortAlgo
    {
      Logic& m_logic;
    public:
      SortAlgo(Logic& n_log):m_logic(n_log){}
      void sort();
      void callLogic(int param);
    };
    
    class Logic
    {
      SortAlgo m_sort;
    public:
      Logic():m_sort(*this){}
      void starteSort();
      void zeichne(int param);
    }
    
    void SortAlgo::callLogic(int param)
    {
      m_logic.zeichne(param);
    }
    
    void SortAlgo::sort()
    {
      //...
    }
    
    void Logic::starteSort()
    {
      m_sort.sort();
    }
    
    void Logic::zeichne(int param)
    {
      //...
    }
    

    Wenn du das Ganze auf verschiedene Header und Quellcode-Dateien aufteilen willst: Logic.h benötigt die SortAlgo.h, SortAlgo.h die Forward-DEklaration und die CPP's benötigen beide Header.



  • Wenn es Dir nichts ausmacht, wäre es klasse, wenn Du mir dazu noch was erklären könntest. Was z. B. macht jetzt genau folgende Zeile?

    SortAlgo(Logic& n_log):m_logic(n_log){}
    

    Ich dachte eigentlich, der ":" sagt aus "erbt von", aber ich verstehe hier nicht ganz den Zusammenhang. Und was steht dann in den geschweiften Klammern? Einfach nichts?

    Leider läßt sich das Ganze so bei mir auch nicht kompilieren, ich erhalte folgende Fehlermeldung:

    logic.o(.text+0x85): In function `Logic::starteSort()':
    quellcode/logic.cpp:50: undefined reference to `SortAlgo::sort()'
    
    40 void Logic::starteSort (){
    50   m_sort.sort();
    51 }
    

    sort() ist bei mir als virtual deklariert, weil die verschiedenen Klassen mit den einzelnen Sortieralgorithmen von SortAlgo erben sollen und dann genau diese Methode unterschiedlich implementieren.
    Der Fehler tritt aber auch auf, wenn ich das "virtual" wegnehme.

    Gruß, Tigger



  • Tigger75 schrieb:

    Wenn es Dir nichts ausmacht, wäre es klasse, wenn Du mir dazu noch was erklären könntest. Was z. B. macht jetzt genau folgende Zeile?

    SortAlgo(Logic& n_log):m_logic(n_log){}
    

    Ich dachte eigentlich, der ":" sagt aus "erbt von", aber ich verstehe hier nicht ganz den Zusammenhang. Und was steht dann in den geschweiften Klammern? Einfach nichts?

    Schau mal in einem schlauen C++-Buch nach "Konstruktor" und "Initialisierungsliste", das hilft dir womöglich weiter (in Kurzform: Das Gebilde dort initialisiert die Member-Variable mit dem übergebenen Parameter 'n_log' - und der Rumpf des Ctors ist leer, weil dort nichts (weiter) gemacht werden muß.

    Leider läßt sich das Ganze so bei mir auch nicht kompilieren, ich erhalte folgende Fehlermeldung:

    logic.o(.text+0x85): In function `Logic::starteSort()':
    quellcode/logic.cpp:50: undefined reference to `SortAlgo::sort()'
    
    40 void Logic::starteSort (){
    50   m_sort.sort();
    51 }
    

    sort() ist bei mir als virtual deklariert, weil die verschiedenen Klassen mit den einzelnen Sortieralgorithmen von SortAlgo erben sollen und dann genau diese Methode unterschiedlich implementieren.

    Hast du auch die richtige Reihenfolge der Definitionen bzw. Header beachtet? Bevor du Logic::starteSort() implementieren kannst, mußt du die Klassendefinition von SortAlgo verfügbar haben.

    PS: eventuell wären an der Stelle Pointer doch geeigneter als Referenzen.



  • Dieser Thread wurde von Moderator/in evilissimo aus dem Forum Andere GUIs - Qt, GTK+, wxWidgets 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.



  • Tigger75 schrieb:

    [/code]

    40 void Logic::starteSort (){
    50   m_sort.sort();
    51 }
    

    sort() ist bei mir als virtual deklariert, weil die verschiedenen Klassen mit den einzelnen Sortieralgorithmen von SortAlgo erben sollen und dann genau diese Methode unterschiedlich implementieren.
    Der Fehler tritt aber auch auf, wenn ich das "virtual" wegnehme.

    Zeig mal deinen Testcode. Hast du evtl. SortAlgo und keine abgeleitete Klasse übergeben? Und wenn die Methode abstrakt sein soll - was einigermaßen sinnvoll erscheint - musst du sie wie folgt deklarieren:

    virtual void sort() = 0;
    

    Davon ab - gibt es einen speziellen Grund warum die Klassen sich gegenseitig kennen müssen?



  • Also, um mal das Grundgerüst zu erläutern:

    Es geht darum, verschiedene Sortieralgorithmen mittels Qt zu visualisieren. Auf der einen Seite gibt es also die Oberfläche und auf der anderen Seite den Kram, den ich gerade versuche zu implementieren.

    Die Logic-Klasse übernimmt das Speichern der Einstellungen, enthält das Array mit den zu sortierenden Werten und soll nun - abhängig vom gerade gewünschten Algorithmus - eine Instanz der erbenden Klasse von SortAlgo erzeugen (was dann das nächste Problem ist).

    SortAlgo (erbt wiederum von QThread) enthält jetzt eine Methode, um zwei Werte zu vertauschen, eine Methode zum Vergleichen zweier Werte und eben die abstrakte Methode "sort()", die durch die erbenden Klassen unterschiedlich implementiert wird. Außerdem soll SortAlgo wiederum eine Funktion der Logic aufrufen, wenn z. B. fertig sortiert ist. Deshalb ist es notwendig, daß die Klassen bzw. eher die Instanzen sich gegenseitig kennen.

    Aber um nochmal ganz vorne anzufangen, ich habe 1:1 den Code von CStoll übernommen und wie folgt aufgeteilt:

    logic.hpp

    #include "sortalgo.hpp"
    
    class Logic
    {
    	SortAlgo m_sort;
    public:
    	Logic():m_sort(*this){}
    	void starteSort();
    	void zeichne(int param);
    };
    

    logic.cpp

    #include "logic.hpp"
    #include "sortalgo.hpp"
    
    void Logic::starteSort(){
    	m_sort.sort();
    }
    
    void Logic::zeichne(int param)
    {
    	int i = param;
    	i += 2;
    }
    

    sortalgo.hpp

    class Logic;
    
    class SortAlgo
    6 {
    	Logic& m_logic;
    public:
    	SortAlgo(Logic& n_log):m_logic(n_log){};
    	void sort();
    	void callLogic(int param);
    };
    

    sortalgo.cpp

    void SortAlgo::callLogic(int param)
    {
    	m_logic.zeichne(param);
    }
    
    void SortAlgo::sort()
    {
    	//...
    }
    

    Erzeugt beim Kompilieren folgende Fehlermeldung:
    In file included from logic.cpp:2:
    sortalgo.hpp:6: error: redefinition of class SortAlgo' sortalgo.hpp:6: error: previous definition ofclass SortAlgo'
    make: *** [logic.o] Fehler 1

    Gruß, Tigger



  • Scheinbar hast du keine include-guards in deinen headern.
    Kurt



  • Bin etwas in Eile, aber auf den ersten Blick: Mach dich über Include-Guards schlau, sprich

    // SortAlgo.hpp
    #ifndef SORTALGO_HPP
    #define SORTALGO_HPP
    
    // Deklaration
    
    #endif // SORTALGO_HPP
    

    und du wirst SortAlgo nicht mehr instanziieren können (ist abstrakt) und wohl auch nicht wollen (Algorithmen austauschen), deshalb

    // Include-Guards nicht vergessen
    
    class Logic
    {
    public:
      Logic() : m_sort(new DefaultSortAlgo(*this)) { }
      ~Logic() { delete m_sort; }
    private:
      SortAlgo* m_sort; // oder noch besser: schau dir Smart-Pointer an,
                        // z.B. boost::shared_ptr
    };
    


  • @finix: So meinte ich das auch, als ich von Pointern gesprochen habe - allerdings würde ich der Logic-Klasse noch einen Konstruktor für SortAlgo* und eventuell eine SetNewAlgo()-Methode spendieren:

    class Logic
    {
    public:
      Logic() : m_sort(new DefaultSort(this)) {}
      Logic(SortAlgo* alg) : m_sort(alg) {m_sort->m_log=this;}
      ~Logic() {delete m_sort;}
    
      void SetAlgo(SortAlgo* alg)
      {
        delete m_sort;
        m_sort=alg;
      }
    
      //Arbeitsmethoden
    private:
      SortAlgo* m_sort;
    };
    
    class SortAlgo
    {
    public:
      friend class Logic;
      SortAlgo(Logic* log=NULL) : m_log(log) {}
      virtual ~SortAlgo() {}
    
      //Arbeitsmethoden - (pur?) virtuell
    private:
      Logic* m_log;
    };
    
    class DefaultSort : public SortAlgo
    {
    public:
      DefaultSort(Logic* log=NULL) : SortAlgo(log) {}
    
      //Arbeitsmethoden - implementiert
    };
    
    //Anwendung:
    Logic l1;//nutzt DefaultSort
    Logic l2(new MySort());//nutzt eigene Klasse MySort
    l1.SetAlgo(new MySort());//Umstellung des Sortier-Algorithmus zur Laufzeit
    

Anmelden zum Antworten