Verwendung eines undefinierten Typs?
-
Folgendes:
Ich habe eine Vertex Klasse die von meiner Point Klasse abgeleitet ist.
class Vertex : public PointDer Konstruktor lautet wie folgt:
typedef double coord; Vertex::Vertex(const coord& x, const coord& y, const coord& z) : Point(x,y,z)Dessweiteren verfüge ich über eine Edge Klasse in der ich versuche, eine Methode der Point Klasse aufzurufen.
In der Edge Klasse verwalte ich die Vertices als Endpunkte einer Kante.
Vertex *vertices[2];Die Methode die ich aufrufe lautet wie folgt:
// Squared length of the edge. double squaredLength() const {return vertices[0]->squaredDistance(vertices[1]);}Die Implementierung der Methode in meiner Point-Klasse schaut wie folgt aus:
//! Squared distance from '*b' double squaredDistance(const Point *b) const {return (((*(this))-(*b)).squaredLength());}Als Fehlermeldung erhalte ich:
Fehler 2 error C2227: Links von "->squaredDistance" muss sich ein Zeiger auf Klassen-/Struktur-/Union-/generischen Typ befinden.
Fehler 1 error C2027: Verwendung des undefinierten Typs "Vertex"Woran kann das liegen?
-
Hallo
Vermutlich fehlt dir ein include auf die Headerdatei wo Vertex deklariert ist.
bis bald
akari
-
Hmmh , hab alles nochmal kontrolliert, aber ein fehlendes include kann ich nicht entdecken.
Dazu meine Edge Klasse:
#include "triangle.h" #include "vertex.h" #include "point.h" class Vertex; class Triangle;Und ähnlich sieht es in allen anderen Klassen aus.
Vertex Klasse:
#include "triangle.h" #include "edge.h" #include "point.h" class Triangle; class Edge;
-
#include "triangle.h" #include "vertex.h" #include "point.h" class Vertex; class Triangle;Macht das sinn ???
warum den vertex forwarden, wenn die deklaration drueber schon steht ???
die include gehoert dann eigentlich nur ins cpp, waehrend der forward ins .h(pp) gehoert ....#include point.h solltest auch ned brauchen, die bringt dir vertex.h schon mit. sollt aber auch ned wirklich stoeren. unsauber waers natuerlich, wenn du im header ein detail von point brauchst .
zumindest beim VS compiler sollt das aber keine probs machen ... er ignoriert den forward dann eigentlich ....
bleibt die frage, bilden class Vertex; als forward und dein class Vertex : public Point ... im header vom vertex.h das selbe symbol ?
Nutzt du namespaces ? sieht aber eigentlich ned so aus ....// Squared length of the edge. double squaredLength() const {return vertices[0]->squaredDistance(vertices[1]);}das ist die stelle wo der compiler motzt ?
aehm wart mal ....
vertex.h included edge.h
edge.h included vertex.hirgendwo muss der compiler mal anfangen
denk mal er faengt mit vertex.h an, das includiert edge.h , also macht er mit edge.h weiter ... das includierd vertex.h ... da er aber schon vertex.h angefangen hat, geht er nur bis zum include guard ... der laesst das ding ueberspringen ...
und voiala, du kommst zu
double squaredLength() const {return vertices[0]->squaredDistance(vertices[1]);}
ohne das vertex.h richtig abgearbeitet wurde ....Bring mal bissi ordnung in dein include chaos
das mit dem forward iss schon ne gute idee, nur richtig umsetzen ...Ciao ...
-
Vertex::Vertex(const coord& x, const coord& y, const coord& z) : Point(x,y,z)mach das draus:
Vertex::Vertex(const coord& x, const coord& y, const coord& z) : public Point(x,y,z)
-
rafilis1982 schrieb:
Die Implementierung der Methode in meiner Point-Klasse schaut wie folgt aus:
//! Squared distance from '*b' double squaredDistance(const Point *b) const {return (((*(this))-(*b)).squaredLength());}Ein schönes Beispiel, das demonstriert, weshalb redundante Klammerung abzulehnen ist.
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.
-
Vertex::Vertex(const coord& x, const coord& y, const coord& z) : public Point(x,y,z)was soll das bringen, bzw funktioniert das überhaupt ?
er ruft den konstruktor der basisklasse auf, von der er
publicableitet
ohne public geht es auch
-
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.
-
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.
-
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::squaredDistancehat 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 SubGrü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?
-
Muss leider weg, aber wenn ich noch eine dumme Frage stellen darf:
Verwendest du Include-Guards?Grüssli
-
//! 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.
-
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);}
-
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());} }
-
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
-
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.