[gelöst] Konstruktor kann nicht aufgerufen werden



  • Was sich sagen lässt, ist dass du in Code-Fragment 2 zwar ein = hinschreibst, das aber eigentlich dem Copy-Constructor entspricht, dort wird also kein operator= erfordert. Beim ersten Codefragment wird aber wirklich ein operator= verlangt. Und der ist aus unerfindlichen Gründen anscheinend nicht zugreifbar. Evtl. ist er private oder die Elternklasse, von der Du erbst, hat den private? Jedoch seltsam, weil dann auch der copy-constructor private sein sollte (Regel der großen drei).

    Code-Fragment 3 ist irrelevant, weil dort nur ein normaler Constructor genutzt wird.

    Ansonsten schließe ich mich camper an.



  • @ camper:
    wow, bist du immer so freundlich zu neulingen?

    @ eisflamme:
    vielen dank für die schnelle Antwort, das Stichwort copyconstructor war schonmal hilfreich. ich konnte das Problem mittlerweile eingrenzen, habe ein workaround gefunden, warum das Problem allerdings besteht, ist mir nicht ersichtlich.

    Es geht dabei um 3 Klassen mit folgender Abhängigkeit:
    Klasse A - besitzt member Klasse B (kann aber den Konstruktor wie oben beschrieben nich aufrufen)
    Klasse B - holt sich im Konstruktor Referenz auf Klasse C
    Klasse C - klassisches Singleton, ergo privater Konstruktor u Zugriff nur über GetInstance()

    Schmeisse ich in B die Referenz auf C raus, habe ich keine Probleme. Das habe ich nun auch gemacht und hole sie mir einfach jedesmal mit GetInstance() neu, handlicher ist das aber nicht. Ich weiss nicht inwiefern es relevant ist, der.Konstruktor von B sieht aber folgendermaßen aus:

    B::B() : _refC(C::GetInstance()) {}
    

    Kann mir damit jemand helfen?
    Liebe Grüße,
    Kraftkornbrot



  • Referenzen müssen im Constructor initialisiert werden, da sie nicht änderbar sind. Was soll operator= also machen, wenn Du eine Zuweisung nutzt?

    Die Frage ist jetzt, was das gewünschte Verhalten bzgl. der Referenz ist, wenn wirklich eine Kopie oder ein Copy-constructor aufgerufen wird. Soll die Referenz kopiert werden, d.h. sollen dann sowohl Original- als auch kopierte Klasse auf dasselbe Objekt verweisen? Oder ist eine Kopie in dem Sinne eigentlich nicht sinnvoll, dann solltest Du copy-ctor und operator= private machen und die Kopie verbieten.

    Wenn es Sinn machen kann, dass A und B beide auf dasselbe Objekt referenzieren und eine Kopie sinnvoll ist, solltest Du die Referenz durch einen Zeiger ersetzen, da der auch nicht besetzt sein kann.

    Edit: Ich sehe gerade, diese Referenz ist ja lediglich ein Singleton-Verweis, dann ist die Variante mit dem Zeiger wohl am einfachsten. Oder Du nimmst die Referenz einfach raus, ist ja sowieso nicht so wichtig.

    Edit2: Und die anderen haben schon Recht, lies Dir Mal den Link durch. Meine Glaskugel funktioniert gerade, aber die habe ich für viel Geld von einem Zauberer geleast (zu anderen Zwecken) und nur zufällig hier rumstehen. Es kann wirklich niemand erwarten, dass das jeder macht.



  • kraftkornbrot schrieb:

    @ camper:
    wow, bist du immer so freundlich zu neulingen?

    Er hat recht.

    ist mir nicht ersichtlich.

    Uns auch nicht mit deinen spaerlichen Codezeile. Hast du dir den Link durchgelesen?

    Wahrscheinlich wird einfach nur der Zuweisungsoperator aufgerufen. Und eine Referenz kann nur einmal initialisiert werden. Aber DU verschweigst uns ja die Fehlermeldung.



  • kraftkornbrot schrieb:

    Es geht dabei um 3 Klassen mit folgender Abhängigkeit:
    Klasse A - besitzt member Klasse B (kann aber den Konstruktor wie oben beschrieben nich aufrufen)
    Klasse B - holt sich im Konstruktor Referenz auf Klasse C
    Klasse C - klassisches Singleton, ergo privater Konstruktor u Zugriff nur über GetInstance()

    class C
    {
    	private:
    		C() {}
    		C(const C&) {}
    		C& operator=(const C&) { return *this; }
    		~C() {}
    
    	public:
    	   static C& GetInstance()
    	   {
    		   static C instance;
    		   return instance;
    	   }
    };
    
    class B
    {
    	private:
    		C& c;
    	public:
    		B() : c(C::GetInstance()) {}
    };
    
    class A
    {
    	private:
    		B b;
    };
    
    int main()
    {
    	A a;
    }
    

    Also ich habe es nach deiner Beschreibung gemacht, und ich bekomme keinen Fehler.

    So, nun lass uns aber mal ernst werden:
    1. Du scheinst mit der C++ Terminologie noch nicht ganz klarzukommen. (Member vs. Klasse vs. Instanz...) Was man unter diesen Begriffen versteht, solltest du in einem guten Buch nochmals nachlesen.

    2. Heutzutage wird Singleton nicht mehr als gut, sondern als schlecht angesehen. Singleton ist ein Anti-Pattern. Wenn du nur eine Instanz willst, dann erstellst du eben nur eine Instanz, ganz einfach. (Fürs Lernen bzgl. static ist es natürlich ok, für den praktischen Einsatz jedoch nicht.)

    3. Camper wollte dir sagen, dass du noch lernen musst, wie man richtig Quellcode postet. Wir wollen ein zusammenhängendes, minimales Codebeispiel, das wir kopieren (Strg+C), in unsere IDE einfügen (Strg+V) und auf kompilieren klicken können. Dann können wir den Fehler anschauen, ihn korrigieren und dir eine vernünftige Antwort posten. Deine Beiträge ist von diesem Szenario noch weit entfernt.



  • mal so dazwischen was offtopic:
    wie geht man eigentlich mit einer referenz als member um?
    ok, man initialisiert sie im construktor. im kopier konstruktor ist das ja auch gut möglich, da ja ein neues objekt erstellt wird und sowas wie die initialisierungsliste gibts auch.
    aber im zuweisungsoperator? wie macht man das da?
    copy&swap geht auch schlecht, denke ich mal, weil in einer swap methode lässt sich die referenz ja auch nicht umstellen.
    die eigentlich frage ist eher wie man referenzen bearbeitet...



  • Danke, das mit dem Zeiger werde ich nachher mal probieren.
    Den Link habe ich mir natürlich durchgelesen, es geht mir auch am wenigsten um die Aussage, sondern um die Art und Weise. Der erste Kontakt mit einer neuen Community ist einfach prägend, camper steht in dem Moment repräsentativ für die gesamte Community, da ich sonst einfach noch keine Vergleichswerte habe.

    Ferner geht es mir hier um ein generelles Verständnis-Problem, daher poste ich auch nur generellen Code, mit einer entsprechenden Beschreibung, die eben alles relevante beinhaltet.

    Zu der Fehlermeldung: die steht bereits im ersten Post.

    Anhand von Eisflammes Post kann ich auch erkennen, dass mein Problem (vorsichtig formuliert) verstanden werden kann, ich denke mit dem von ihm geschriebenen lässt sich das ganze auch lösen (ich kann es nur gerade nicht ausprobieren). Sollte jemand das ganze nicht verstanden haben, dann braucht diese Person nicht antworten. Und wenn ich nach 3 Tagen keine Antwort bekommen habe, dann mache ich mir meine Gedanken dazu und frage notfalls nach, woran es liegt. (wie gesagt, ein Hinweis darauf stört mich nicht, solange er nett formuliert ist.)

    Zum eigentlichen Thema: sobald ich das ganze ausprobieren konnte, mir nochmal in Ruhe Gedanken machen konnte und es verstanden (oder eben nicht) habe, editier ich hier rein.

    Vielen Dank für eure schnellen Antworten.



  • es wurde schon alles machbare gesagt, eigentlich.
    du hast keinen passenden operator= (zuweisungsoperator) für deine klasse implementiert oder ihn verdeckt/verboten.

    int main()
    {
        FreeCamera _freeCamera;  //geht, d.h. du hast einen default konstruktor
        _freeCamera = FreeCamera(/*Parameter*/); // geht nicht, sagst du, daher keine zuweisungsoperator
    
        FreeCamera _fC = FreeCamera(/*Parameter*/); // daraus lässt sich schliessen, dass dein kopierkonstruktor vorhanden ist
    }
    

    das sind meine mutmaßungen, da kannst du was zu sagen...



  • Skym0sh0 schrieb:

    mal so dazwischen was offtopic:
    wie geht man eigentlich mit einer referenz als member um?
    aber im zuweisungsoperator? wie macht man das da?

    Ich denke mal, man verbietet ihn. Ansonsten handelt man sich ja nur Inkonsistenzen ein, wenn man nur den einen Teil des Objekts kopiert, den anderen Teil aber nicht.


  • Mod

    kraftkornbrot schrieb:

    @ camper:
    wow, bist du immer so freundlich zu neulingen?

    ja, wobei ich nicht zwischen Neulingen und anderen unterscheide.

    kraftkornbrot schrieb:

    wie geht man eigentlich mit einer referenz als member um?
    ok, man initialisiert sie im construktor. im kopier konstruktor ist das ja auch gut möglich, da ja ein neues objekt erstellt wird und sowas wie die initialisierungsliste gibts auch.
    aber im zuweisungsoperator? wie macht man das da?

    Refernzen als Member sind fast immer ein Designfehler, sie bieten gegenüber konstanten Zeigern keine Vorteile (Syntax ist irrelevant, schliesslich ist die Referenz nicht public), dafür mehrere Nachteile:
    - man kann keine Zeiger-auf-Member bilden,
    - es gilt nicht mehr sizeof(Member1)+sizeof(Member2)+... <= sizeof(Klasse)

    Im Übrigen ist ein const bei Membern meist auch fehl am Platz.

    Sinnvoll sind Memberreferenzen eigentlich nur bei Dingen wie Proxyobjekten. Kein Wunder, schliesslich ist ja ein Proxy im Prinzip so etwas wie eine Referenz. Und dann stimmt die Semantik der compilergenerierten Funktionen plötzlich wieder.



  • ok, sowas dachte ich mir nämlich.
    ganz unter uns, ich hab noch nie referenzen als member gebraucht, nur als parameter bei funktionen



  • camper schrieb:

    Refernzen als Member sind fast immer ein Designfehler, sie bieten gegenüber konstanten Zeigern keine Vorteile (Syntax ist irrelevant, schliesslich ist die Referenz nicht public), dafür mehrere Nachteile:
    - man kann keine Zeiger-auf-Member bilden,
    - es gilt nicht mehr sizeof(Member1)+sizeof(Member2)+... <= sizeof(Klasse)

    Ich stimme zu, dass Referenzmember nur selten verwendet werden sollten, allerdings bin ich der Meinung, dass deine Nachteile in den meisten Fällen irrelevant sind. Oder wann spielt die sizeof -Bedingung so im Code eine Rolle?

    Ein kleiner Vorteil von Referenzen ist, dass man deutlich macht, dass der Verweis nicht auf NULL zeigt, und dies auch vom Compiler prüfen lässt. Hängt aber vom Stil ab. Früher habe ich ab und zu Referenzen bei Funktoren verwendet, jedoch wird dann der Zuweisungsoperator nicht generiert, daher tendiere ich zu Zeigern.

    camper schrieb:

    Im Übrigen ist ein const bei Membern meist auch fehl am Platz.

    D.h. du würdest doch nicht konstante Zeiger, sondern veränderliche Zeiger als Alternative zu Referenzen vorschlagen? In dem Fall käme wieder der Nachteil zum Tragen, dass keine Initialisierung erzwungen wird.


  • Mod

    Nexus schrieb:

    camper schrieb:

    Refernzen als Member sind fast immer ein Designfehler, sie bieten gegenüber konstanten Zeigern keine Vorteile (Syntax ist irrelevant, schliesslich ist die Referenz nicht public), dafür mehrere Nachteile:
    - man kann keine Zeiger-auf-Member bilden,
    - es gilt nicht mehr sizeof(Member1)+sizeof(Member2)+... <= sizeof(Klasse)

    Ich stimme zu, dass Referenzmember nur selten verwendet werden sollten, allerdings bin ich der Meinung, dass deine Nachteile in den meisten Fällen irrelevant sind. Oder wann spielt die sizeof -Bedingung so im Code eine Rolle?

    Ein kleiner Vorteil von Referenzen ist, dass man deutlich macht, dass der Verweis nicht auf NULL zeigt, und dies auch vom Compiler prüfen lässt. Hängt aber vom Stil ab. Früher habe ich ab und zu Referenzen bei Funktoren verwendet, jedoch wird dann der Zuweisungsoperator nicht generiert, daher tendiere ich zu Zeigern.

    Würde das ein Compiler an dieser Stelle prüfen? Meist wird ja die Referenz an etwas gebunden werden, was als Konstruktorargument übergeben wurde - vorzugsweise als Referenz. Dann könnte die - sofern der Compiler so etwas überhaupt tut - an dieser Stelle prüfen.

    Das Nicht-Null-sein-können-Argument halte ohnehin für relativ schwach - mehr als die Intention des Programmierers ist damit erst mal nicht dargestellt, und das gehört ins Interface - mithin Funktionsparameter. Ich bin dort sehr für die Verwendung von Referenzen.

    Ein weiterer Nachteil, der mir einfällt, wäre dass die entsprechende Klasse kein Standard-Layout hat.

    Nexus schrieb:

    camper schrieb:

    Im Übrigen ist ein const bei Membern meist auch fehl am Platz.

    D.h. du würdest doch nicht konstante Zeiger, sondern veränderliche Zeiger als Alternative zu Referenzen vorschlagen? In dem Fall käme wieder der Nachteil zum Tragen, dass keine Initialisierung erzwungen wird.

    const bei einem einzelnen Member bedeutet, dass dieser Member unabhängig von der Konstanz des Klassenobjektes kostant ist. Dann kann es sich aber eigentlich nicht mehr um objektbezogene Daten handeln, und es stellt sich die Frage, wieso der Member nicht gleich statisch ist.
    Häufiger sieht man das hier ja, wenn mal wieder ein Singleton gebaut werden soll - aus der bloßen Tatsache, dass nur ein Klassenobjekt existieren soll, und das auch noch konstant ist, wird gefolgert, dass es logisch wäre, die Member gleich als konstant zu deklarieren.
    Ein Problem der Initialisierung sehe ich eigentlich nicht. Schließlich ist es doch nicht der Compiler, der vorgibt, was zu initialisieren ist, sondern der Programmierer, der etwas mit dem Member tun will.

    Zum const beim Member zwingt dich der Compiler nicht, das programm wird auch funktionieren ohne const. Konsequenterweise sollte const nur dann dort benutzt werden, wenn es eine zusätzliche Aussage über das Programm macht (das ist typischerweise z.B. bei Funktionsargumenten der Fall, deswegen gilt dort meist: immer const, wenn möglich).



  • camper schrieb:

    const bei einem einzelnen Member bedeutet, dass dieser Member unabhängig von der Konstanz des Klassenobjektes kostant ist. Dann kann es sich aber eigentlich nicht mehr um objektbezogene Daten handeln, und es stellt sich die Frage, wieso der Member nicht gleich statisch ist.

    Nun, wenn aber ein konstanter Member abhaengig von bspw. Konstruktorparametern ist? Dann muss er trotzdem seperat fuer jede Instanz existent sein und initialisiert werden.

    Das Nicht-Null-sein-können-Argument halte ohnehin für relativ schwach - mehr als die Intention des Programmierers ist damit erst mal nicht dargestellt, und das gehört ins Interface - mithin Funktionsparameter.

    👍
    Sowieso kann man auch folgendes machen, wenn man komplett bedeppert ist:

    int foo(std::string& ref);
    
    foo( *reinterpret_cast<std::string*>( nullptr ) );
    

    Referenzen arbeiten intern auch mit Zeigern, nur die Zeigerverwendung wird vor dem Programmierer verborgen.

    aus der bloßen Tatsache, dass nur ein Klassenobjekt existieren soll, und das auch noch konstant ist, wird gefolgert, dass es logisch wäre, die Member gleich als konstant zu deklarieren.

    Wenn ich das jetzt richtig verstanden habe, ist das etwas verdammt daemliches und unnoetiges. Wer tut sowas 😞

    D.h. du würdest doch nicht konstante Zeiger, sondern veränderliche Zeiger als Alternative zu Referenzen vorschlagen? In dem Fall käme wieder der Nachteil zum Tragen, dass keine Initialisierung erzwungen wird.

    Aber der Vorteil bei Zeigern ist ja unter anderem, dass sie verschiedene Objekte referenzieren koennen, und nicht an eines Gebunden sind ( ➡ Referenz). Ich sehe also keinen Vorteil von konstanten Zeigern gegenueber Referenzen.

    Initialisierung kann man aber auch mit non-static data member initializers erzwingen.



  • @camper: Du hast Recht, durch den Konstruktor-Funktionsparameter kann man schon recht viel über die Intention aussagen und vom Compiler absichern. Auch bezüglich const -Member war ich deiner Meinung (habe früher auch Ähnliches hier geschrieben), nur habe ich die Aussage "Referenzen bieten gegenüber konstanten Zeigern keine Vorteile" zunächst verstanden, als ob sich als Alternative konstante Zeiger anböten.

    @Sone: Das "bedeppert"-Argument ist nichtssagend, mit Absicht kann man alles falsch machen. Ebenso irrelevant in dieser Diskussion ist die interne Repräsentation von Referenzen. Und Vorteile von konstanten Zeigern gegenüber Referenzen hat camper mittlerweile mindestens drei aufgezählt 🙄



  • Nexus schrieb:

    Und Vorteile von konstanten Zeigern gegenüber Referenzen hat camper mittlerweile mindestens drei aufgezählt 🙄

    Ich denke, irgendwie andersherum - er hat Nachteile von Referenzen aufgezaehlt 🤡

    Aber klar, haste Recht. Allerdings dachte ich immer, man kann die Adresse einer Referenz nehmen... und das die Groesse einer Referenz auch der Groesse des Referenzierten Objektes entspricht...



  • Also ich nehme immer Referenzen, wenn es möglich ist (nicht nullifizierbar ist an manchen Stellen genau richtig und gut), so auch innerhalb der Klasse. Den einzigen wirklichen Nachteil (bis auf obige Ausnahmen) sehe ich wirklich darin, dass operator= nicht mehr funktioniert, während copy-ctor eben doch funktioniert. Ich meine, nach Gesetz der großen drei sollte es nicht so sein, dass nur der operator= nicht funktioniert, oder? Das spricht für mich gleichzeitig aber genau so gegen einen konstanten Zeiger, solange man eben nicht sowieso copy-ctor geblockt hat, oder?



  • So, an dieser Stelle nochmal ein großes Dankeschön an alle, habe viel aus euren Posts gelernt. Das Problem, um das es ursprünglich mal ging konnte ich auch lösen, indem die Referenz durch einen Pointer ersetzt wurde, wie Eisflamme es vorgeschlagen hatte.
    Liebe Grüße



  • camper schrieb:

    kraftkornbrot schrieb:

    wie geht man eigentlich mit einer referenz als member um?
    ok, man initialisiert sie im construktor. im kopier konstruktor ist das ja auch gut möglich, da ja ein neues objekt erstellt wird und sowas wie die initialisierungsliste gibts auch.
    aber im zuweisungsoperator? wie macht man das da?

    Refernzen als Member sind fast immer ein Designfehler, sie bieten gegenüber konstanten Zeigern keine Vorteile

    Ähm doch. Die können nicht Null sein.

    camper schrieb:

    dafür mehrere Nachteile:
    - man kann keine Zeiger-auf-Member bilden,

    Habe ich noch nie gemacht und werde ich auch nie. Und wenn man so etwas doch mal braucht, kann man ja einen Zeiger nehmen.

    camper schrieb:

    - es gilt nicht mehr sizeof(Member1)+sizeof(Member2)+... <= sizeof(Klasse)

    Wen interessiert das?

    camper schrieb:

    Im Übrigen ist ein const bei Membern meist auch fehl am Platz.

    Weil man das Objekt dann nicht kopieren kann? Die meisten Klassen sind ohnehin nicht fürs Kopieren gedacht. Im Nachhinein betrachtet ist es ein Design-Fehler von C++, dass Klassen standardmäßig kopierbar sind. Das ist zusätzliches Verhalten, das man nicht explizit deaktivieren müssen sollte.

    Nexus schrieb:

    Früher habe ich ab und zu Referenzen bei Funktoren verwendet, jedoch wird dann der Zuweisungsoperator nicht generiert, daher tendiere ich zu Zeigern.

    Früher ist nicht jetzt.

    camper schrieb:

    Ein weiterer Nachteil, der mir einfällt, wäre dass die entsprechende Klasse kein Standard-Layout hat.

    .. was überhaupt keine Rolle spielt, wenn man es nicht braucht (Hinweis: Man braucht es nie).

    EDIT: Wirre Zitate mit entsprechenden Antworten:

    Nexus schrieb:

    Ein kleiner Vorteil von Referenzen ist, dass man deutlich macht, dass der Verweis nicht auf NULL zeigt, und dies auch vom Compiler prüfen lässt. Hängt aber vom Stil ab.

    Es hängt vom Stil ab, ob eine Referenz nicht Null sein kann?

    camper schrieb:

    Meist wird ja die Referenz an etwas gebunden werden, was als Konstruktorargument übergeben wurde - vorzugsweise als Referenz.

    Als was denn sonst?

    camper schrieb:

    Das Nicht-Null-sein-können-Argument halte ohnehin für relativ schwach - mehr als die Intention des Programmierers ist damit erst mal nicht dargestellt, und das gehört ins Interface - mithin Funktionsparameter. Ich bin dort sehr für die Verwendung von Referenzen.

    Was soll man damit sonst darstellen? Nicht-Null heißt nicht-Null.

    Sone schrieb:

    Das Nicht-Null-sein-können-Argument halte ohnehin für relativ schwach - mehr als die Intention des Programmierers ist damit erst mal nicht dargestellt, und das gehört ins Interface - mithin Funktionsparameter.

    👍
    Sowieso kann man auch folgendes machen, wenn man komplett bedeppert ist:

    int foo(std::string& ref);
    
    foo( *reinterpret_cast<std::string*>( nullptr ) );
    

    Kann man nicht, das ist undefiniertes Verhalten.
    static_cast würde es auch tun.

    Sone schrieb:

    Referenzen arbeiten intern auch mit Zeigern, nur die Zeigerverwendung wird vor dem Programmierer verborgen.

    Oder so ähnlich..


  • Mod

    @TyRoXx: wenn das ein ernsthafter Diskussionsbeitrag sein soll, bitte ich darum, das noch einmal neu zu verfassen. So hat das leider nur NadrW-Niveau.


Anmelden zum Antworten