Verwendung eines undefinierten Typs?



  • An einen Fehler bezüglich der Inkludierung hatte ich auch schon gedacht...

    ..nur wie kriegt man das eleganter und auch funktionsfähig hin?

    Fassen wir mal zusammen:

    Meine Triangle Klasse:

    #include "edge.h"
    #include "vertex.h"
    #include "misc.h"
    #include "point.h"
    

    Edge und Vertex Klasse wie oben beschrieben.

    Nun habe ich ein wenig rumgetüftelt...[b]

    Leider ohne Erfolg:
    Ich dachte mir, da ich in der Edge und Vertex klasse, ja auch triangles.h inkludiere, kann ich die Inkludierung der Edge und Vertex Header außen vor lassen.

    Doch es kamen nur mehr Fehler, der genannten Art. Warum auch immer!

    Lasse ich die Forwards weg, ebenfalls mehr Fehler.

    Ich muss sagen, ich bin ein wenig irritiert.

    Wie habe ich die Includes zwischen meiner Triangle/Edge/Vertex/Point Klasse aufzubauen?

    Ich muss vlt noch dazu sagen, dass dieses Konstrukt bisher einwandfrei lief, bis ich meine Point Klasse hinzugenommen habe und die genannte Methode implementierte.


  • Mod

    Ich wiederhole mich sehr ungerne.
    Dein Problem hat nicht direkt etwas mit der Reihenfolge der der #include-Direktiven zu tun und kann darüber entsprechend auch nicht gelöst werden.


  • Administrator

    camper schrieb:

    Bei der Definition von Point ist die Klasse Vertex noch unvollständig definiert (ganz klar und das hat nichts mit includes zu tun, schließlich hängt die Definition von Vertex ja von der Definition von Point ab). Das heißt aber auch, dass Vertex innerhalb jeder Funktion, die inline in der Definition von Point definiert wird, unvollständig ist. Offensichtlich kann in diesem Falle also die Funktion Point::squaredDistance nicht in der Klasse definiert werden, sondern nur außerhalb, nachdem zusätzlich die Definition von Vertex gesehen wurde.

    Also das nimmt mich jetzt selber wunder, da ich deine Lösung nicht begreife. Die ersten beiden Sätze sind absolut klar, logisch und einleuchtend. Der dritte Satz, welcher ich hervorgehoben habe, ist für mich irgendwie unlogisch. Die Funktion Point::squaredDistance hat doch überhaupt nichts mit Vertex am Hut. Vertex wird nirgends verwendet in dieser Funktion, muss somit auch nicht definiert sein.

    @rafilis1982,
    Falls sich camper wirklich irren sollte, was ich mir zwar fast nicht vorstellen kann, so wäre es interessant, wenn du mal von deinen Headern den Anfang postest, damit man sich einen Überblick machen kann. Ca. in der Art:

    // Beispiel.h
    
    // Includes, bsp:
    #include "OtherHeader.h"
    
    // Predeklaration, bsp:
    class Test;
    
    // Klassenkopf, bsp:
    class Test : public Sub
    

    Grüssli



  • Kann ich gerne machen:

    Ich beschränke mich mal auf meine Edge und Vertex Klasse, da wohl hier der Fehler liegt

    #include "triangle.h"
    #include "vertex.h"
    #include "point.h"
    
    class Vertex;
    class Triangle;
    
    class Edge
    {..}
    
    #include "triangle.h"
    #include "edge.h"
    #include "point.h"
    
    class Triangle;
    class Edge;
    
    class Vertex : public Point
    {...}
    

    @camper
    Ich kann deinen Schilderungen leider auch nicht ganz folgen.

    Wenn ich dich richtig verstanden habe, müsste ich dann ja nahezu jede Methode aus der Point Klasse ausklammern oder nicht? 😕

    Ist denn nicht möglich, die Point Klasse so zu nutzen wie Sie existiert?


  • Administrator

    Muss leider weg, aber wenn ich noch eine dumme Frage stellen darf:
    Verwendest du Include-Guards?

    Grüssli


  • Mod

    //! Squared distance from '*b'
     double squaredDistance(const Point *b) const {return (((*(this))-(*b)).squaredLength());}
    

    schreibe ich das mal um, so dass es lesbar wird, haben wir hier

    return (*this-*b).squaredLength();
    

    Hier brauchen wir offensichtlich einen operator-, der zu Point gehört, und - wie ich annehme - ein Edgeobjekt liefert. Dazu muss Edge hier bereits vollständig definiert worden sein. Umgekehrt benötigt aber Edge::squaredLength eine vollständige Definition von Vertex. Und die Definition von Vertex benötigt eine vollständige Definition von Point. Folglich muss wenigstens eine der angesprochen Memberfunktionen außerhalb der Klasse definiert werden.
    (ich war irrtümlich davon ausgegangen, dass der operator- von Point ein Vertex liefert, und kein Edge; aber für das Grundproblem spielt dieser Unterschied eben keine Rolle).
    Ein etwas liberaler Umgang mit Informationen zum Code (vulgär: mehr Code) wäre zweifellos hilfreich gewesen.


  • Administrator

    Hach, wusste ich es doch. Camper MUSS recht haben 😃
    Hab übersehen, dass sehr wahrscheinlich die Minus-Operation ein Edge-Objekt zurückgibt. Jetzt ist es natürlich klar. Ich frage mich sogar gerade, ob die Sache nicht etwas rekursiv ist?
    Edge::squaredLength -> Point::squaredDistance -> Point::operation -() -> Edge -> Edge::squaredLength ...

    Grüssli



  • Da muss ich leider widersprechen 😃

    Der '-' Operator liefert ein Point Objekt zurück
    und ruft folgende Methode aus der Point Klasse auf:

    double squaredLength() const {return (x*x + y*y + z*z);}
    

  • Mod

    rafilis1982 schrieb:

    Da muss ich leider widersprechen 😃

    Der '-' Operator liefert ein Point Objekt zurück
    und ruft folgende Methode aus der Point Klasse auf:

    double squaredLength() const {return (x*x + y*y + z*z);}
    

    Ich verweise mal auf den letzten Satz meines vorigen Beitrages. Bei Glaskugelraten kommt eben oft nichts Sinnvolles heraus.
    Was wir brauchen ist die vollständige Definition aller hier relevanten Klassen + ggf. die Angabe wie wo in welcher Reihenfolge inkludiert wird + ggf. die Deklarationen relevanter freier Funktionen.



  • Naja, was brauchst du denn noch an Infos?

    Die Klassendefinitionen von Triangle,Edge,Vertex habe ich angegeben, sowie die Methoden und entsprechende Aufrufe.

    Der Aufruf und die Methoden sind jeweils im Header implementiert (const).

    Das Objekt was erzeugt wird, ist wie ich bereits sagte ein Objekt vom Typ der Klasse Point.

    Sieht dann so aus:

    class Point
    {
    double squaredLength() const {return (x*x + y*y + z*z);}
    
     double squaredDistance(const Point *b) const {return (((*(this))-(*b)).squaredLength());}
    }
    

  • Administrator

    Du hast wohl ca. 3 Möglichkeiten:
    1. Du beantwortest noch die Frage mit dem Include-Guard. Wenn du nämlich keine hast, dann dürfte das schon mal einiges erklären.
    2. Du erstellst ein minimal Beispiel, von welchem du den ganzen Quellcode hier ins Forum stellst, wo der gleiche Fehler allerdings auch auftritt.
    3. Du stellst deinen aktuellen Quellcode hier ins Forum. Also die ganzen Header und wenn möglich auch noch die Implementierungen. Allerdings ist die Wahrscheinlichkeit dann klein, dass sich das überhaupt jemand durchliest.

    Wenn du include-Guards verwendest, dann spielt die Reihenfolge, in welche du deine Header inkludierst wohl kaum eine Rolle. Ich kann mit den Informationen, welche du uns gegeben hast, jedenfalls nichts erkennen.
    Die unnötigen Predeklarationen, welche du verwendest, kann man zwar wirklich weglassen, sollten dem Code aber keinen Schaden anrichten.

    Grüssli


  • Mod

    rafilis1982 schrieb:

    Die Klassendefinitionen von Triangle,Edge,Vertex habe ich angegeben, sowie die Methoden und entsprechende Aufrufe.

    wo?

    Das Objekt was erzeugt wird, ist wie ich bereits sagte ein Objekt vom Typ der Klasse Point.

    Macht in meinen Augen keinen Sinn, aber hier geht es uns ja nicht um Semantik (Länge eines Punktes?). Jedenfalls machen die gleichen Funktionsnamen klar, wieso ich verwirrt war, welche Funktion hier welche aufrufen soll.
    Was wir somit wissen ist, dass die Definition von Edge::squaredLength auf die Definition von Vertex (und mittelbar Point) angewiesen ist, also nach deren Definition erfolgen muss. Dafür musst du irgendwie sorgen.

    Lese ich den ersten Post auf dieser Seite, wird sofort klar, dass hier auch ein Problem mit exzessiven #include besteht.
    Edge.h inkludiert vertex.h
    vertex.h inkludiert edge.h
    das kann offensichtlich nicht gut gehen, jedenfalls hängt die engültige Reihenfolge des Codes dann davon ab, welcher Header in der .cpp-Datei als erstes inkludiert wird.

    Der Fakt, dass du sowohl den Header inkludieren willst als auch gleichzeitig Forwarddeklarationen einführst, indiziert, dass diese Problematik noch nicht richtig durchdacht wurde. Grundsätzlich solltest du entweder den Header für eine Klasse einbinden oder eine bloße Forwarddeklaration durchführen (eine 3. Möglichkeit kommt in Frage, falls du Funktionen zwar im Header aber außerhalb der Klassendefinition definierst; dann kann es angezeigt sein, erst eine Forwarddeklaration durchzuführen, dann die Klasse, die definiert werden soll, zu definieren, und dann den Header für die Klasse, die zuvor nur definiert wurde, einzubinden). Beides zu tun, ist im besten Falle überflüssig, im schlechtesten Falle führt es zu zirkulären Abhängigkeiten wie oben.


Anmelden zum Antworten