Morgen.
ich habe das wohl ein prinzipielles Verständnisproblem. Ich habe einen
Constructor in dem arrays allokiert werden. Im copyconstructor soll die
selben arrays allokiert werden. Anstatt copy&paste zu verwenden möchte
ich den Constructor aus dem Copyconstrutor aufrufen.
Warum kann ich den Constructor nicht wie unten (unter "geht nicht")
aufrufen. Es compiliert und ich kann in den Constructor debuggen. Nach
dem zurücksprungen in den Copyconstrcuctor beinhalten sind die attribute
m_pPOI und m_PWaypoint keine gültigen Adressen, die aber im Constructor
gesetzt werden.
Im ersten Fall funktioniert es, also was genau ist hier der Unterschied?
Oder ist es einfach ein Compilerproblem da nicht offensichtlich ist dass
die pointer verändert werden?
1
CRoute::CRoute(intmaxWp,intmaxPOI){
2
[...]
3
m_pPOI=newCPOI*[m_maxPOI];
4
m_pWaypoint=newCWaypoint[m_maxWp];
5
}
6
7
// geht, m_pPOI und m_pWaypoint sind gültige pointer
Dein erstes Beispiel verwendet sog. delegate-constructors und ist erst
mit C++11 valide. Vorher ging das auch nicht.
Deine zweite Variante legt auf dem lokalen Stack im Constructor ein
zweites Objekt vom Typ CRoute an. Da es keiner Variablen zugewiesen
wird, wird es danach gleich wieder gelöscht (temporary).
Ist genauso wie:
std::string("Hallo");
zu schreiben.
Du hast mal Java programmiert, richtig?
Grüße,
RSp
Ronny Spiegel schrieb:> Dein erstes Beispiel verwendet sog. delegate-constructors und ist> erst> mit C++11 valide. Vorher ging das auch nicht.
Das ist mir nicht aufgefallen, wie hätte ich es vorher gemacht?
> Deine zweite Variante legt auf dem lokalen Stack im Constructor ein> zweites Objekt vom Typ CRoute an. Da es keiner Variablen zugewiesen> wird, wird es danach gleich wieder gelöscht (temporary).>> Ist genauso wie:>> std::string("Hallo");>> zu schreiben.
Ok, d.h. es kann nicht als Funktionsaufruf des Constructors
interpretiert werden? Kann man ihn dazu zwingen?
> Du hast mal Java programmiert, richtig?
Naja eigentlich nicht. Habs mal gelernt aber das is lange her.
Papa schrieb:> Ronny Spiegel schrieb:>> Dein erstes Beispiel verwendet sog. delegate-constructors und ist>> erst>> mit C++11 valide. Vorher ging das auch nicht.> Das ist mir nicht aufgefallen, wie hätte ich es vorher gemacht?
z.B. mit privaten init-Methoden, die vom jeweiligen Konstruktor gerufen
werden. Finde ich persönlich unschön. Braucht man ja jetzt gottseidank
nicht mehr - sofern der Arbeitgeber einen vernünftigen Compiler einsetzt
:)
>> Deine zweite Variante legt auf dem lokalen Stack im Constructor ein>> zweites Objekt vom Typ CRoute an. Da es keiner Variablen zugewiesen>> wird, wird es danach gleich wieder gelöscht (temporary).>>>> Ist genauso wie:>>>> std::string("Hallo");>>>> zu schreiben.> Ok, d.h. es kann nicht als Funktionsaufruf des Constructors> interpretiert werden? Kann man ihn dazu zwingen?
Nein.
>> Du hast mal Java programmiert, richtig?> Naja eigentlich nicht. Habs mal gelernt aber das is lange her.
Ist nämlich in Java völlig normal, Constructors so zu bauen.
Grüße,
RSp
Die eigentlich wichtigere Frage ist aber, warum du der Ansicht bist, die
Arrays selbst allokieren zu müssen, anstatt Standard-Container
einzusetzen, wie zb. einen std::vector?
Die kümmern sich selbst um diese Details wie Copy Constructor oder auch
Zuweisungsoperator und Destructor. Und was noch viel wichtiger ist: die
vergrößern sich auch bei Bedarf, so dass du bei deiner Route im Vorfeld
gar nicht wissen musst, wieviele Points of Interest bzw. Waypoints es
geben wird bzw. kann.
Ronny Spiegel schrieb:> Papa schrieb:>> Ronny Spiegel schrieb:>>> Dein erstes Beispiel verwendet sog. delegate-constructors und ist>>> erst>>> mit C++11 valide. Vorher ging das auch nicht.>> Das ist mir nicht aufgefallen, wie hätte ich es vorher gemacht?>
Ok danke, dann is mir das soweit klar.
> z.B. mit privaten init-Methoden, die vom jeweiligen Konstruktor gerufen> werden. Finde ich persönlich unschön. Braucht man ja jetzt gottseidank> nicht mehr - sofern der Arbeitgeber einen vernünftigen Compiler einsetzt> :)
Ja gut daran hab ich auch gedacht. Es geht hier aber nicht um die
Funktionalität sondern um das Verständnis.
Karl Heinz schrieb:> Die eigentlich wichtigere Frage ist aber, warum du der Ansicht> bist, die> Arrays selbst allokieren zu müssen, anstatt Standard-Container> einzusetzen.>> Die kümmern sich selbst um diese Details wie Copy Constructor oder auch> Zuweisungsoperator. Und was noch viel wichtiger ist: die vergrößern sich> auch bei Bedarf, so dass du bei deiner Route im Vorfeld gar nicht wissen> musst, wieviele Points of Interest bzw. Waypoints es geben wird bzw.> kann.
Es ist die Aufgabenstellung ;-) Is fürs Studium. Malen nach Zahlen (C++
Programmieren nach Vorgabe). Im Prinzip kann ich programmieren, nur mein
Stil ist mehr funktional C als Objektorientier C++, deswegen kam ich nie
in die Verlegenheit mit solchem Copyconstructor Bla bla gerade WEIL ich
sonst stark für die STL-Container und Libraries bin.
Papa schrieb:>> Die kümmern sich selbst um diese Details wie Copy Constructor oder auch>> Zuweisungsoperator. Und was noch viel wichtiger ist: die vergrößern sich>> auch bei Bedarf, so dass du bei deiner Route im Vorfeld gar nicht wissen>> musst, wieviele Points of Interest bzw. Waypoints es geben wird bzw.>> kann.>> Es ist die Aufgabenstellung ;-) Is fürs Studium.
Dann ist das ok.
Es schadet nicht, wenn man selbst da mal (ein paar mal) durch musste und
sich um die dynamischen Allokierungen in allen Details selbst kümmert.
Zu Ausbildungszwecken.
> Malen nach Zahlen (C++> Programmieren nach Vorgabe). Im Prinzip kann ich programmieren, nur mein> Stil ist mehr funktional C als Objektorientier C++, deswegen kam ich nie> in die Verlegenheit mit solchem Copyconstructor Bla bla gerade WEIL ich> sonst stark für die STL-Container und Libraries bin.
Sehr gut. Dann will ich nichts gesagt haben. :-)
Wichtig: wenn man es ganz richtig machen will, dann wird das recht
heftig. Denn dann muss man sich im Konstruktor auch um fehlgeschlagene
Allokierungen kümmern und dann kann das recht schnell ausarten. Daher
wird auch oft die Devise ausgegeben: Pro Klasse nur EINE dynamisch
verwaltete Resource. Das würde dann in deinem Fall dazu führen, dass du
für den Teil 'Verwaltung einer Menge von PoI in Form von Pointern auf
die richtigen PoI' eine eigene Klasse einführst UND dasselbe für die
Waypoints.
d.h. deine Klassen sehen so aus
1
classCPOIPtrArray
2
{
3
...
4
};
5
6
classCWaypointArray
7
{
8
...
9
};
10
11
classCRoute
12
{
13
....
14
15
private:
16
CPOIPtrArraym_POIs;
17
CWayPointArraym_Waypoints;
18
};
Nebeneffekt: die CRoute Klasse braucht jetzt wieder keinen CCtor, keinen
ZuweisungsOp und auch keinen Destructor. Dafür handeln die
Verwaltungsklassen diese Details wieder für sich selbst.
Unterschätze sowas nicht, denn diese Veraltungsklassen können sich im
weiteren Verlauf nämlich wieder als nützlich erweisen. Zb ein einer
Zeichenfunktion die so ein WaypointArray bekommt. Dann kannst du in
diese Zeichenfunktion zb das WaypointArray aus einer Route reingeben, du
kannst aber auch 'on-the-fly' ein WaypointArray zb aus gelesenen
GPS-Koordinaten zusammenstellen und diese dann mit derselben
Zeichenfunktion malen lassen OHNE zuvor eine Route erzeugt haben zu
müssen.
So ein paar Guide-Lines für die OOP:
Durchdenk deine Aufgabenstellung genau, durchaus schon ein bischen bis
in die Details: Alles was dir beim 'Niederschreiben' als Hauptwort
unterkommt, ist meistens ein heißer Kandidat für eine Klasse.
Klassen sind faul. Sie tun nichts lieber als Teilprobleme an andere
Klassen zu delegieren.
Bei OOP dreht sich sehr viel um Zuständigkeiten. Du musst dir immer die
Frage stellen: Ist diese Klasse für die Funktionalität überhaupt
zuständig. Ist es ihr Bier dieses oder jenes zu berechnen, oder ist da
nicht eigentlich eine andere Klasse (zb der Member eines Objekts) dafür
zuständig? In dem Fall delegiert dann ein Objekt sofort diese
Funktionalität an seinen Member. Gibt es keinen derartigen Member, dann
könnte sowas ein Hinweis darauf sein, dass einer ins System einzuführen
ist.
Ich hätte das sowieso anders gemacht. Das is eine alberne pointer,
reference, array und bla geschubserei. Zweck der Sache ist es mit
Pointern und Pointer auf Pointern usw zu arbeiten.
Sinnvoll finde ich die ganze Architektur nur bedingt, aber mich fragt ja
eh keiner ;-)
Aber es bringt mich (wieder einmal) zu dem Punkt dass ich zugeben muss,
wirklich objektorientiert programmieren kann ich bis heute nicht. Ich
drifte immer wieder in prozeduale Muster ab und vewende Klassen meist
als intelligente Funktionen.
Papa schrieb:> Aber es bringt mich (wieder einmal) zu dem Punkt dass ich zugeben muss,> wirklich objektorientiert programmieren kann ich bis heute nicht. Ich> drifte immer wieder in prozeduale Muster ab und vewende Klassen meist> als intelligente Funktionen.
Ja, das dauert.
Ich würde sagen, ich hab so 3 bis 4 Jahre gebraucht, bis ich OOP
komplett verinnerlicht habe.
Also jetzt nicht einfach nur 'class' hinschreiben und die Funktionen
rutschen in die class hinein. Sondern die ganze Thematik: wie baut man
ein Klassensystem auf, wie benutzt man es, wann unterteil man in
Klassen, Zuständigkeiten, wie arbeitet man mit Klassen etc. etc.
Am Anfang gings mir wie dir: ich sah OOP einfach nur als eine
Zusammenfassung von struct+Funktionen und im Grunde habe ich C++ so
programmiert, wie auch in C. Mit der Zeit (und mit einem Kollegen) hab
ich mich mehr in Richtung OOP entwickelt, was dann dazu führte, dass wir
uns verzettelt haben und viel zu viele Klassen auf das Problem geworfen
haben. Im Laufe der Jahre entwickelt man dann ein Gefühl dafür, was
sinnvoll ist und wo der Overkill anfängt und das System nicht mehr
einfacher wird, sondern unübersichtlicher und komplexer.
Geholfen hat mir zb viel das Studium von Scott Meyers "Effective C++".
Dann natürlich die GoF "Design Patterns" und vom Herb Sutter mit seiner
regelmässigen "Guru of the week" Kolumne hab ich auch viel gelernt,
obwohl es da oft mehr um irgendwelche Details ging.
Ronny Spiegel schrieb:> Ist nämlich in Java völlig normal, Constructors so zu bauen.
Also erst mal gibt es in Java keinen "Copy-Konstruktor" und zweitens
würde man da entweder ein 'super' oder ein 'this' benötigen und ganz
sicher kein neues Objekt erstellen. Das wiederum würde in JS
funktionieren.
Läubi .. schrieb:> Ronny Spiegel schrieb:>> Ist nämlich in Java völlig normal, Constructors so zu bauen.>> Also erst mal gibt es in Java keinen "Copy-Konstruktor" und zweitens
1. Hab ich das nicht behauptet, oder?
2. Könnte man einen bauen, der aber explizit aufgerufen werden muss
> würde man da entweder ein 'super' oder ein 'this' benötigen und ganz
Syntaktische Feinheiten hab ich mal aussen vor gelassen, zumal ich in
Java auch nicht mehr so fit bin.
Es ging einfach nur darum, dass Konstruktoren an andere Konstruktoren
delegieren können. Das ist ein Feature, was es in Java schon (immer?)
gibt und dort auch entsprechend benutzt wird. Daher wird das
erfahrungsgemäß oft von Java-Entwicklern beim Umstieg auf C++
eingesetzt, mit dem Erfolg, dass der erzeugte Code nicht wie gewünscht
funktioniert.
Grüße,
Rooney
Was in C++ leider auch nicht sehr offensichtlich ist: Die Konstruktoren
machen auch die Initialisierung der vtable. Das ist fuer den Entwickler
aus seinem Code heraus nicht ersichtlich - bis er auf Ideen wie den
manuellen Aufruf von Konstruktoren kommt. Damit kann man sich schoen die
schon gemacht Initialisierung wieder zerschiessen.
cybmorg schrieb:> Was in C++ leider auch nicht sehr offensichtlich ist: Die Konstruktoren> machen auch die Initialisierung der vtable. Das ist fuer den Entwickler> aus seinem Code heraus nicht ersichtlich - bis er auf Ideen wie den> manuellen Aufruf von Konstruktoren kommt.
Es ist eher umgekehrt: Man kann Konstruktoren ganz einfach nicht manuell
aufrufen. Man kann nur Objekte erzeugen, und als Teil der Erzeugung wird
der Konstruktor automatisch aufgerufen.