BigThree Problem
-
Kann mir bitte jemand den AssignmentOp und den CopyCtor von Container so implementieren, dass folgendes Programm funzt? Ich stehe im Moment etwas auf dem Schlauch

#include <iostream> using namespace std; class ABC { public: virtual void func()=0; }; class Foo : public ABC { public: void func() { cout << "Ich bin func aus Foo\n"; } }; class Bar : public ABC { public: void func() { cout << "Ich bin func aus Bar\n"; } }; template<typename T> class Container { private: T* matrix_[2]; public: Container(ABC* first, ABC* second) { matrix_[0]=first; matrix_[1]=second; } ~Container() { delete matrix_[0]; delete matrix_[1]; } Container(const Container<T>& c) { //wie implementieren? } Container operator=(const Container<T>& c) { //wie implementieren? return *this; } }; int main() { Container<ABC> a(new Foo(), new Bar()), b(new Bar(), NULL), c(a); a=b; return 0; }
-
1. nutzt du das template nicht, sondern codest den typ ABC fest rein.
2. geht das?: matrix_[2] ????Zuweisungoperator:
void oparator=(Container<T> ziel, Container<> quelle)
{
ziel.getMatrix() = quelle.getMAtrix();
//muss natürlich für jeden wieder überladen werden
//und getMAtrix muss ne REferenz zurückgeben, weil es ja private isetc....
}jedenfalls vom prinzip her......
-
dev_MAddoX schrieb:
1. nutzt du das template nicht, sondern codest den typ ABC fest rein.
Hast natuerlich recht. Ich meine natuerlich
T* matrix_[2];dev_MAddoX schrieb:
2. geht das?: matrix_[2] ????
warum sollte es nicht?
dev_MAddoX schrieb:
Zuweisungoperator:
void oparator=(Container<T> ziel, Container<> quelle)Was soll das denn?
Ich will den operator= doch nicht als friend function implementieren.dev_MAddoX schrieb:
ziel.getMatrix() = quelle.getMAtrix();Dann wuerde ich nur die Zeiger kopieren und nicht die Objekte.
Aber genau das ist mein Problem, die Matrix zu kopieren.
Ich haette gerne sowas gemacht:Container operator=(const Container<T>& c) { if(this == &c) return; for(int i=0; i<2; ++i) delete matrix_[i]; for(int i=0; i<2; ++i) if(c.matrix[i] == NULL) this->matrix_[i] = NULL; else this->matrix_[i] = new T(c.matrix_[i]); return *this; }Haette glaube ich auch hingehaun(haette es??), waere die Klasse nicht generisch.
Weil ich sie aber mit dem Typ ABC parametrisiert habe(der ja abstrakt ist) funktioniert new T(c.matrix_[i]); schon mal gar nicht.
Hat jemand schonmal sowas gehabt?thx in advance
-
Wie kommst du eigentlich darauf dass du dich darum kümmern müsstest ?
Der typ sollte einen vernünftigen assignment-op und copyctor implementieren und dann kannst die benutzen.
const Container &operator=(const Container<T>& c) { if(this == &c) return; *matrix_[0]=c.get_matrix1(); //op= des enthaltenen typen *matrix_[1]=c.get_matrix2(); return *this; }Für den copy-ctor genau so.
-
Argh...
musst natürlich noch dereferenzieren.
const Container &operator=(const Container<T>& c) { if(this == &c) return; *matrix_[0]=*c.get_matrix1(); //op= des enthaltenen typen *matrix_[1]=*c.get_matrix2(); return *this; }überseh ich jetzt was wesentliches ?
-
KurzeFrage schrieb:
Argh...
musst natürlich noch dereferenzieren.
const Container &operator=(const Container<T>& c) { if(this == &c) return; *matrix_[0]=*c.get_matrix1(); //op= des enthaltenen typen *matrix_[1]=*c.get_matrix2(); return *this; }überseh ich jetzt was wesentliches ?
IMHO schon.
Was passiert mit den vorherigen Elementen der Matrix?*matrix_[0]=*c.get_matrix1(); //op= des enthaltenen typenWas ist nun mit dem Element, das vorher an *matrix_[0] stand?
Du hast es nicht deleted, also hast du nun ein schoenes memory leak.
-
Nein hat er nicht, die bekommen neue werte.
Er kopiert keinen speicherbereich sondern , weisst die klasse(ABC in diesem fall) an die werte zuzuweisen. Was ja auch richtig ist weil nur sie weiss wie man das am besten macht.
-
Einverstanden.
Ich habe aber unter meinen Elementen auch NULL Pointer.
Ich behandele diese wie folgt:Container operator=(const Container<T>& c) { if(this != &c) { for(int i=0; i<2; ++i) if(c.matrix_[i] == NULL) { delete this->matrix_[i]; this->matrix_[i] = NULL; } else { //Wer sagt mir, dass *this->matrix_[i] != NULL ist? *this->matrix_[i] = *c.matrix_[i]; } } return *this; }Falls mir ein NULL Pointer beim kopieren von einem Containerobjekt A unterkommt, delete ich das Element und setze es auf NULL. Wenn nun auf A erneut der operator= aufgerufen wird, dann schlaegt folgende Anweisung fehl:
//Wer sagt mir, dass *this->matrix_[i] != NULL ist? *this->matrix_[i] = *c.matrix_[i];
-
Du könntest einfach testen ob es NULL ist. Da du ja sowieso das element löschen würdest in diesem fall, machst du einfach nichts mit diesem element oder wäre das nicht im sinne des erfinders ?
//EDIT NOCHMAL ... machst du doch nicht, bleibt dir in diesem fall also nichts übrig als nochmal zu testen, dann würdest du eben ein neues element anlegen müssen, dafür könntest zum beispiel den copy-ctor der klasse benutzen.
if(matrix[i]==NULL) matrix[i]=new T(*c.matrix[i]);
-
Und schon waeren wir beim Ausgangsproblem.
Weil ich sie aber mit dem Typ ABC parametrisiert habe(der ja abstrakt ist) funktioniert new T(c.matrix_[i]); schon mal gar nicht.
-
Dann musst du einen weg finden dass keine NULL-pointer auftauchen. Das ist ja normalerweise auch eine ausnahme und ich würde da eine exception werfen. Möglich wäre doch zum beispiel einen leeren typ zu definieren oder sowas. Sodass du imma mit validen objekten arbeitest, die eben nur nicht notwendigerweise imma auch definierte werte haben.
-
Dann musst du einen weg finden dass keine NULL-pointer auftauchen.
Finde ich keine befriedigende Loesung

Die NULL Pointer brauche ich, um zu erkennen, ob das Feld meiner Matrix leer ist.
Und immer ein Test mit instanceof find ich auch nicht gut, wenn ich einen leeren Typ anlege.Das new Problem(matrix[i]=new T(*c.matrix[i]);) wuerde sowieso spaetestens im CopyCtor erneut auftreten, weil ich da auf jeden Fall Speicher anfordern muss.
Container(const Container<T>& c) { for(int i=0; i<2; ++i) this->matrix_[i] = new T(c.matrix_[i]); }Angenommen, ich liesse mich auf deinen Vorschlag ein, dann gaebe es aber noch folgendes Problem:
*this->matrix_[i] = *c.matrix_[i];Diese Technik called immer den operator= von T, also von ABC.
Um dieses Problem zu loesen muesste ich den operator= in ABC virtual definieren.
Das zoege nach sich, dass alle Klassen in meinem Vererbungsgraphen zuweisungskompatible zueinander sind.
Sowas waere also Problemlos moeglich:class ABC { public: virtual ABC& operator=(const ABC&){} }; class KlasseA_dieNichtsMit_B_zuTunHat : public ABC { public: KlasseA_dieNichtsMit_B_zuTunHat operator=(const KlasseA_dieNichtsMit_B_zuTunHat& A) { ABC::operator=(A); } }; class KlasseB_dieNichtsMit_A_zuTunHat : public ABC { public: KlasseB_dieNichtsMit_A_zuTunHat operator=(const KlasseB_dieNichtsMit_A_zuTunHat& B) { ABC::operator=(B); } }; void sample(ABC& a, ABC& b) { a=b; //unsinnig, aber leider erlaubt } int main() { KlasseA_dieNichtsMit_B_zuTunHat A; KlasseA_dieNichtsMit_B_zuTunHat B; sample(A,B); }Durch die Namen angedeutet, kann man erkennen, dass KlasseA_dieNichtsMit_B_zuTunHat
und KlasseA_dieNichtsMit_B_zuTunHat nichts miteinander zu tun haben, ausser eine gemeinsame ABC. Trotzdem koennte ich sie einander zuweisen.
In den Klassen meiner Vererbungshierarchie existiert eigentlich kein solcher Isomorphismus, dass ich so etwas wollte.
-
Hmm ich versteh das problem ehrlich gesagt nicht.
Im copy-ctor kann man locker mit dem blosen assignment-op der enthaltenen klasse arbeiten. Die erzeugung der objekte wäre dann auch wieder nicht deine aufgaben. Da wäre dann ein
container.insert(new derived());angebracht.
Und naja ein container soll ja wenn er was enthält auch was enthalten was sinnvoll ist, darum geht es doch gerade. Ich versteh auch nicht warum die beiden abgeleiteten klassen, wenn sie nichts miteinander zu tun haben, dann von der selben basisklasse erben. In diesem moment haben sie was gemeinsam, nämlich die basis. Wenn du das nicht willst dann musst du deinem container eben sagen dass er nicht container der basisklasse ist sondern jeweils einen container für die abgeleiteten klassen instanzieren.
class A{ }; class B : public A{ }; class C : public A{ }; container<A*> container_A_; container<B*> container_B_; container<C*> container_C_; container_A_.insert(new B()); container_A_.insert(new C()); container_B_.insert(new B()); container_C_.insert(new C()); //conatainer_B_=container_C_ schlaegt dann fehlOder überseh ich wieder was ?
-
prolog schrieb:
Hmm ich versteh das problem ehrlich gesagt nicht.
Im copy-ctor kann man locker mit dem blosen assignment-op der enthaltenen klasse arbeiten.
ohne vorher speicher zu allozieren? das wuerde mich sehr wundern, nachdem man mir hier versicherte genau das tun zu muessen.
Die erzeugung der objekte wäre dann auch wieder nicht deine aufgaben. Da wäre dann ein
container.insert(new derived());Sicher, das wuerde das Problem loesen, wenn ich wuesste, dass ich wirklich gerade ein derived kopiere und nicht ein anderes von ABC abgeleitetes Objekt derived2.
Leider weiss ich aber nicht, welche Instanz ich von meinen 12 von ABC abgeleiteten Klassen gerade kopiere. D.h. es muesste ein Typtest her und der ist ganz sicher nicht im Sinne des Erfinders.class ABC; class A : public ABC { /* blablabla */ }; class B : public ABC { /* */}; class C : public ABC... class D.... ... class Container //enthaelt ABC Objekte Container(const Container& c) { for(int i=0; i<1000; ++i) if(c.matrix_[i] instanceof A) this->matrix_[i] = new A(c.matrix_[i]); else if(c.matrix_[i] instanceof B) this->matrix_[i] = new B(c.matrix_[i]); else if(c.matrix_[i] instanceof C) this->matrix_[i] = new C(c.matrix_[i]); else if(c.matrix_[i] instanceof D) this->matrix_[i] = new D(c.matrix_[i]); //und so weiter... //ich kann keine Typen nachtraeglich hinzufuegen, ohne eine weitere Verzweigung hinzuzufuegen. //gaaanz schlecht!! } };Ich versteh auch nicht warum die beiden abgeleiteten klassen, wenn sie nichts miteinander zu tun haben, dann von der selben basisklasse erben. In diesem moment haben sie was gemeinsam, nämlich die basis.
Nur die Basis. Das heisst noch lange nicht, dass sie den selbem abstrakten Status haben, der fuer einen virtuellen assingnmentOp notwendig waere. Nur weil mehrere Klassen von derselben ABC erben, will ich doch noch lange nicht, dass man sie alle einander gegenseitig zuweisen kann
class Shape { protected: int x,y; }; class Square : public Shape { }; class Circle : public Shape { }; void sample(Shape& a, Shape& b) { a=b; } int main() { Square a; Circle b; sample(a,b); // vollkommen unsinnig!!! }Vielleicht verstehe ich dich auch nicht, dann koenntest du dich ja an dem Codefragment probieren, dass ich anfangs gepostet hatte. Waere gespannt auf deine Loesung.
-
Gehört TGGC eigentlich auch zu den Big Three?
-
naaa schrieb:
Gehört TGGC eigentlich auch zu den Big Three?
Nein, dafür ist er zu schlecht.
-
ich denke mal HumeSikkins und volkard gehören auf jeden Fall dazu. Aber wer noch?

-
och leute....
-
Ok, also wenn du weisst dass du nur abgeleitete klassen verwalten musst dann brauchst du keine templates. Du arbeitest eben mit den basisklassenzeigern.
Dass man keine instanz einer abstracten klass erzeugen kann liegt in der natur der c++-dinge, da wirst du nichts dran drehen können. Was du willst ist offensichtlich eine deep-copy-semantic beim op= und copy-ctor. Gut dann musst
du aber dafür sorgen dass du nie mit null-pointern zu tun hast. Weil sonst immer das problem mit der instanzierung der basis auftritt. Der container ist nicht für allocierung bzw. deallocierung verantwortlich. Wenn der container leer ist enthält er kein objekt, wenn er die größe 1 hat dann enthält er eben ein definiertes objekt. Es ist aufgabe des clients dafür zu sorgen dass da ordentliche werte vorhanden sind um damit arbeiten zu können wie ers erwartet.Kannst du mal sagen warum du diesen weg überhaupt gehst mit dem eigenen container ? Ich meine einen groben umriss des kontexts geben, dass man mal schaun kann ob das nicht auch anders geht ?
Ich würde wahrscheinlich boost::array <basis*> verwenden. Aber es kann ja sein dass das für dich nich ausreicht weil du noch irgendwas besonderes machen willst. Aber vom jetzigen standpunkt aus verschliesst sich mir irgendwie der sinn des ganzen.
Ansonsten kannst du auch einfach ne shallow-copy der zeiger machen, musst halt nur drauf achten dass die zeiger nicht ausversehen durch einen andren container zerstört werden. Deswegen sollte der container auch die elemente nicht im dtor oder ähnliches freigeben. Dafür ist auch der client verantwortlich.
Sry nochmal, das muss frustrierend für dich sein aber probiers doch nochmal genau zu schildern bitte.
-
big three schrieb:
ich denke mal HumeSikkins und volkard gehören auf jeden Fall dazu. Aber wer noch?

TGGC

-
Ok, also wenn du weisst dass du nur abgeleitete klassen verwalten musst dann brauchst du keine templates. Du arbeitest eben mit den basisklassenzeigern.
Gut, dann werde ich meine Klasse ungenerisch machen.
Dass man keine instanz einer abstracten klass erzeugen kann liegt in der natur der c++-dinge, da wirst du nichts dran drehen können. Was du willst ist offensichtlich eine deep-copy-semantic beim op= und copy-ctor.
Ja

Gut dann musst
du aber dafür sorgen dass du nie mit null-pointern zu tun hast. Weil sonst immer das problem mit der instanzierung der basis auftrittIch brauchte halt einen Wert, der mir signalisiert, dass in einem Feld kein ABC Objekt vorhanden ist. Der NULL Pointer bot sich IMHO dafuer an.
Der container ist nicht für allocierung bzw. deallocierung verantwortlich.
Wie jetzt? Wer dann? Ich wuesste nicht, wie ich beim CopyCtor um eine Allokation herumkommen koennte.
Kannst du mal sagen warum du diesen weg überhaupt gehst mit dem eigenen container ? Ich meine einen groben umriss des kontexts geben, dass man mal schaun kann ob das nicht auch anders geht ?
Ich brauchte einige spezielle member functions, die kein std container bereitstellt. Meine Container Klasse ist auch nur ganz kurz und eigentlich
recht simpel.Es geht mir im Moment nicht so sehr darum, dass ich ja viel einfacher eine bereits fertige Containerklasse verwenden koennte.
Das eigentliche Problem liegt darin: Ich habe eine Klasse, die ein Attribut vom Typ Zeiger auf ABC hat. Ich habe mich jetzt gefragt, wie ich den CopyCtor und den AssignmentOp zu implementieren habe, um das Attribut zu kopieren, ohne seinen genauen Typ zu wissen(weil ich ja 12 Unterklassen habe) und dabei noch die NULL Pointer angemessen behandeln zu koennen.
std::vector etc koennen das doch auch!
Wie machen die das denn?
Mir kommt das Problemm so alltaeglich vor!