eingebettete Objekte
-
Hi,
selbst mit duensten krieg ichs nicht frittiert

Ja, ich weiss nicht, wie ich die Punktklasse als Membervariablen in die Linienklasse einbette. Das Problem liegt evtl. im Implementierungsteil, zumindest meckert der Compiler in diese Richtung:
> g++ -c -g main.cpp Pt_2d.cpp Line_2d.cpp GeoObj.cpp reports.cpp
Line_2d.cpp:20: error: prototype for ‘Line_2d::Line_2d(std::string, Pt_2d, Pt_2d, long int)’ does not match any in class ‘Line_2d’
Line_2d.h:9: error: candidates are: Line_2d::Line_2d(const Line_2d&)
Line_2d.h:18: error: Line_2d::Line_2d(std::string, Pt_2d&, Pt_2d&, long int)Mit meinem Miniwissen tippe ich mal auf ein Problem mit Zeiger und oder Namensraum?
Torsten
-
Die Signatur von Deklaration und Definition vom Konstruktor ist unterschiedlich. In der Deklaration (in der Header-Datei) gibst du als Parameter Referenzen auf Punkte an, in der Definition (cpp-Datei) einfach "nur" Punkte. Da fehlt das "&".
-
Hi fdfdg,
danke, der Compiler schweigt!. Beim vielen rumfriemeln hatte sich gleich noch ein anderer Fehler eingeschlichen.
Zumindest haut die Initialisierung hin und die Reportmethode der Basisklasse sieht das Linien-Objekt... Fuer den Anfaenger, wie mich haenge ich nochmal den berichtigten Implementierungsteil der Linienklasse an.Dank & Gruss, Torsten
// ------------------------------------ Line_2d.cpp -- #include "Pt_2d.h" #include "Line_2d.h" #include "GeoObj.h" #include <iostream> #include <string> #include <sstream> using namespace std; // constr Line_2d::Line_2d(std::string newname, Pt_2d::Pt_2d &newp1, Pt_2d::Pt_2d &newp2, long int idx) : GeoObj(newname, idx) { pt1 = &newp1; pt2 = &newp2; //std::cout << "Create Feature Line(" << "test" << "," << "test" << ")\n"; } // destr Line_2d::~Line_2d() { std::cout << "Drop Line "; }
-
Also etwas als Referenz entgegenzunehmen, und sich dann einen Zeiger darauf zu merken, ist schon relativ ... eigenartig.
Soll heissen: jemand der mit einer Klasse arbeiten soll, die sowas macht, wird wohl kaum damit rechnen, und u.U. die übergebenen Punkte löschen bevor er die Linie löscht.Warum nicht einfach die Punkte "by value" in der Linie speichern?
-
Line_2d::Line_2d(std::string newname, Pt_2d::Pt_2d &newp1, Pt_2d::Pt_2d &newp2, long int idx) // warum Pt_2d::Pt_2d ? Pt_2d reichtSo wie du deine Klassen anlegst muss man erst 2 Punkte erschaffen und dann eine Linie. Die erschaffenen Punkte müssen im Scope bleiben wenn die Linie gültig sein will, das ist bis jetzt kein Problem - im Endeffekt bekommst du dann aber Seiteneffekte - sobald sich einer der Punkte ändert, ändert sich auch die Linie. Ist das beabsichtigt? Wenn nicht, guck dir nochmal Parameterübergabe perValue und perReference an.
Was meinst du passiert wenn jemand das hier macht:
Line_2d line("Kurve", Pt_2d(1,1,1), Pt_2d(5,4,2), 3);Das mit den Ids ist auch unpraktisch ... der User könnte einfach gleiche IDs verteilen ... wenn du die Objecte eindeutig über die Id ansprechen magst kapsel das in dem BaseObj:
// base.h class Base { static int maxIdSoFar; int id; public: Base() : id(maxIdSoFar++) {} }; // !!!! base.cpp #include "base.h" int Base::maxIdSoFar = 0;Wenn du Verständnigsprobleme hast, melde dich. Sollte die ID eher eine Art "Gruppierungsfunktion" haben, nenn sie besser nicht id sondern wasauchimmer und verpass ihr nen defaultwert im Konstruktor für "mir ist egal welcher gruppe dieses Objekt angehört" ala:
class Base1 { int wasauchimmer; std::string name; public: Base1(std::string NaMe, int WasAuchImmer=0) : name(NaMe), wasauchimmer(WasAuchImmer) { .... } };
-
Hi hustbaer, padreigh...
danke fuer eure Hinweise! Ihr puhlt in der Wunde
Als "Durchschnittsscriptschreiber" muss ich mich erstmal ein bischen in C++ zurechtfinden.Mein Ziel ist eine Art strikte Objekthierarchie (bin kein Master of the oop-Terminologie). Meine Annahmen sind:
# ========================================================================
// -- Basisklasse --------------------------------------------------------
Container fuer Datenhaltung/Reports & (noch) keine Ahnung was noch...// -- Punktklasse --------------------------------------------------------
Sollte immer zuerst erzeugt werden; enthaelt punktspezifische Methoden...// -- Linien-/Flaechenklassen --------------------------------------------
Diese sollten nur die Relationen zwischen den Punkten enthalten sowie linien- und flaechenspezifische Methoden... D.h. z.B., dass die Lageaenderung eines Punktes gleichzeitig das Linien- oder Flaechenobjekt betrifft. Wird eine Linie geloescht, betrifft das gleichzeitig die Punkte. Wird ein Punkt geloescht, muessen (irgendwie) die Relationen der betreffenden hoeherhierarchischen Objekte "on-the-fly" upgedated werden, incl. Gueltigkeitsprüfung. D.h. eine Fläche muesste nach einem "Punktupdating" automatisch checken, ob sie noch eine Flaeche ist. (...sonst selfkill of Flaeche
). Daher muss man wohl intensiv mit Zeigern/Referenzen arbeiten... Und ich nur Freizeitscriptschreiber... 
# ========================================================================Soweit der Hintergrund zu meinem c++-Training. Ich habe jetzt die Wertuebergabe wie folgt gestaltet:
#ifndef LINE_2D_H_ #define LINE_2D_H_ #include "GeoObj.h" #include "Pt_2d.h" #include <string> class Line_2d : public GeoObj { private: Pt_2d *pt1; Pt_2d *pt2; public: // constr Line_2d(std::string newname, Pt_2d newp1, Pt_2d newp2, long int idx); std::string report_single(); // destr ~Line_2d(); }; #endif /*LINE_2D_H_*/Im Implementationsteil kann ich aber nicht mehr auf die eigentlichen Punktobjekte zugreifen:
Line_2d::Line_2d(std::string newname, Pt_2d newp1, Pt_2d newp2, long int idx) : GeoObj(newname, idx) { pt1 = &newp1; pt2 = &newp2; // DAS GEHT... std::cout << "Create Feature Line(" << "test" << "," << &newp1 << ")\n"; // DAS GEHT NICHT std::cout << "Create Feature Line(" << "test" << "," << *pt1 << ")\n"; cout << newp1.Pt_2d::report_single(); }Was mache ich falsch??? Warum kann ich nicht mit dem *pt1-Zeiger arbeiten???
THX, Torsten
-
Weil es in c++ Unterschiede gibt je nach dem was du machst, ganz Grob (da du offensischtlich nicht nach perRef perVal googlen magst:
kompilier das hier mal und Spiele rum, verstehen was wo warum crashed:
#include <iostream> void aus(int a, int &b, int * c) { std::cout << "i, j, k, *k" << i << ", " << j << ", " << k << ", "; if (k!=0) std::cout << *k; else std::cout << "n.a."; std::cout << std::endl; } void m(int a, int &b, int * c) { a += 10; b *= 2; *c = 1000; } int main() { int i = 21; int j = 22; int * k = 0; aus(10,20,0); m(10,20,0); aus(i,j,0); m(i,j,&j); aus(i,j,0); aus(i,j,k); m(i,j,k); aus(i,j,k); k = new int(24); aus(i,j,k); m(i,j,k); aus(i,j,k); delete k; }
-
Ich bin zwar nicht Mr. Zeiger, aber das Grundprinzip von Zeigern etc. habe ich verstanden

Bei meinen Objekten bin ich mir aber trotzdem nicht sicher...
Ich glaube folgendes zu tun:-
Ich kreiere 2 Punkte und eine Linie mit jenen in main():
Pt_2d p1("Punkt1", 0, 4, 0);
Pt_2d p2("Punkt2", 1, 1, 1);
Line_2d l1("Line1",p1,p2,2); -
Ich uebergebe fuer die Initialisierung des Linienobjektes die beiden Punkte
als (FRAGE:) Zeiger?...
this von z.B. p1 enthaelt eine andere Adresse als &newp1 -
Ich weise dem Zeiger *pt1 (FRAGE:) die Adresse meines
Punktobjektes pt1 = &newp1; zu?
Rufe ich jetzt eine report-Methode in der Punkt-Klasse auf, geht es zwar mit &newpt1 aber nicht mit pt1 (siehe Codeschnipsel #1). Laut Compileroutput zeigt pt1 mitnichten auf das Punktobjekt:
$> g++ -c -g main.cpp Pt_2d.cpp Line_2d.cpp GeoObj.cpp reports.cpp
Line_2d.cpp: In constructor ‘Line_2d::Line_2d(std::string, Pt_2d, Pt_2d, long int)’:
Line_2d.cpp:37: error: request for member ‘Pt_2d::report_single’ in ‘((Line_2d*)this)->Line_2d::pt1’, which is of non-class type ‘Pt_2d*’Entweder geht das generell nicht so, wie gedacht, oder ich hab mich im Adressraum verirrt
?Danke, Torsten
// Headerdatei fuer Linienobjekt class Line_2d : public GeoObj { private: Pt_2d::Pt_2d *pt1; Pt_2d::Pt_2d *pt2; public: // constr Line_2d(std::string newname, Pt_2d::Pt_2d newp1, Pt_2d::Pt_2d newp2, long int idx); // destr ~Line_2d(); }; // Implementierungsdatei fuer Linienobjekt // constr Line_2d::Line_2d(std::string newname, Pt_2d newp1, Pt_2d newp2, long int idx) : GeoObj(newname, idx) { pt1 = &newp1; pt2 = &newp2; std::cout << "Create Feature Line(" << "test" << "," << &newp1 << ")\n"; std::cout << "Create Feature Line(" << "test" << "," << pt1 << ")\n"; cout << newp1.Pt_2d::report_single(); // #1 Compiliert nicht cout << pt1.Pt_2d::report_single(); } // destr Line_2d::~Line_2d() { std::cout << "Drop Line "; }
-
-
Du solltest wirklich mal nach call by value, call by reference googeln, dir anschauen was temporäre objekte sind und wie man memberfunktionen über pointer aufruft.
Was du möchtest ist sicherlich in etwa folgendes:
// Headerdatei fuer Linienobjekt class Line_2d : public GeoObj { private: Pt_2d *pt1, *pt2; public: Line_2d(std::string newname, Pt_2d &newp1, Pt_2d &newp2, long int idx); ~Line_2d(); }; // Implementierungsdatei fuer Linienobjekt Line_2d::Line_2d(std::string newname, Pt_2d &newp1, Pt_2d &newp2, long int idx) : GeoObj(newname, idx), pt1(&newp1), pt2(&newp2) { std::cout << "Create Feature Line(" << "test" << "," << &newp1 << ")\n"; std::cout << "Create Feature Line(" << "test" << "," << pt1 << ")\n"; cout << newp1.report_single(); // Compiliert auch cout << pt1->report_single(); } // destr Line_2d::~Line_2d() { std::cout << "Drop Line "; }
-
Hi inter2k3,
1000Dank! Der "Pfeil" macht den Unterschied... Es kompiliert und meine Punktmethoden funktionieren. Bischen unklar ist mir noch, warum beide Konstruktoren (siehe unten) bisher nichts am generellen Verhalten aendern. Ich kann mit beiden Versionen meine Punkte verschieben, neu setzen usw. Mein C++-Buch sagte mir, dass die zweite Variante dazu da ist, automatisch (in diesem Fall) zwei neue Punktobjekte zu kreieren. Andererseits wird ja auf eine bestehende Adresse verwiesen. Puhh...
Danke fuer die Suchtips.Torsten
Line_2d::Line_2d(std::string newname, Pt_2d &newp1, Pt_2d &newp2, long int idx) : GeoObj(newname, idx) // ERGIBT DAS GLEICHE, WIE: Line_2d::Line_2d(std::string newname, Pt_2d &newp1, Pt_2d &newp2, long int idx) : GeoObj(newname, idx), pt1(&newp1), pt2(&newp2)
-
Du machst es dir echt schwer ... und schränkst deine Klassen stark ein - Respektive schaffst dir schwer zu debuggende Fehlerquellen.
Dein Ansatz sorgt dafür das die Punkte die du zum Konstruieren der Linie benutzt IMMMER im Scope bleiben müssen damit deren Adressen noch haltbar sind - alternativ müsstest du die Punkte mit "new" anlegen - und dann sage ich dir Speicherlecks ohne Ende vorher. Es wäre sauberer, wenn eine Linie eigene Kopien der Punkte bekommt, die dann auch unabhängig von den Punkten sind mit denen du sie "erschaffen" hast. Wenn du gerne die Punkte einer Linie als Punkte umherschieben willst, solltest du sie dir vorher von der Linie wieder holen.
Compilier und start mal ... und denk nach:
#include <iostream> struct Punkt { int x; int y; Punkt(int X,int Y) : x(X), y(Y) {std::cout << "Construct:"; report();} ~Punkt() { std::cout << "Destruct:"; report(); } void report() { std::cout << "\t(" << x << "," << y << ")\tadressX " << &x << "\tadressY" << &y << std::endl; } }; struct Linie { Punkt * p1; Punkt * p2; Linie (Punkt & P1, Punkt & P2) : p1(&P1), p2(&P2) {} }; int main() { // das hier geht Punkt ol1 (10,10); Punkt ur1 (20,20); Linie l1 (ol1,ur1); Linie l2 (l1); // das hier geht nicht: { Punkt ol2 (1,1); Punkt ur2 (2,2); l2 = Linie (ol2,ur2); } // std::cout << ol2.x; std::cout << "Using: "; l2.p1->report(); }Das ganze läuft bei mir in dem Beispiel überigens ohne Fehler und mit richtigem Ergebnis ... überleg mal warum.
Besser wäre daher:
struct Punkt { int x; int y; Punkt(int X,int Y) : x(X), y(Y) {std::cout << "Construct:"; report();} Punkt(const Punkt & p) {std::cout << "Copying:"; p.report(); x = p.x; y = p.y;} ~Punkt() { std::cout << "Destruct:"; report(); } void report() const { std::cout << "\t(" << x << "," << y << ")\tadressX " << &x << "\tadressY" << &y << std::endl; } }; struct Linie { private: Punkt p1; Punkt p2; public: Linie (const Punkt & P1, const Punkt & P2) : p1(P1), p2(P2) {} Punkt & startPunkt() { return p1; } Punkt & endPunkt() { return p2; } };
-
@padreigh: Das "besser waere daher"-Beispiel laeuft nun auch nicht grade rund. War wahrscheinlich eine Aufgabe fuer mich.
Trotzdem Danke @moment, ich versuch erstmal weiter zu friemeln...
Torsten
-
Dorstne schrieb:
@padreigh: Das "besser waere daher"-Beispiel laeuft nun auch nicht grade rund. War wahrscheinlich eine Aufgabe fuer mich.
Trotzdem Danke @moment, ich versuch erstmal weiter zu friemeln...
Torsten
Doch tut es

Du musst natürlich die Zeile:l2.p1->report(); // in mainersetzen durch:
l2.startPunkt().report();