class in class initialisieren



  • Hallo,

    ich hab folgendes Problem, ich möchte in der Klasse
    ein klassen Objekt &meinY haben...
    weiters habe ich noch das Problem das ich ein Objekt Y& _meinY anscheinend
    auch im leer Constructor initialisieren muss, wie mache ich das?

    da das jetzt schwer zu erklären ist hier der C# code:

    class X { 
    
            private Y meinY;
            public X(){}
            public X(ref Y m, int n, int k) {
                meinY = m;
            }
            public Boolean move() {
                return true;
            }
        }
    
        class Y {
            public Y() { }
            public Y(int i) { }
        }
    

    C++ Code:

    class X {
    private:
      Y& _meinY;
    public:
      X();
      X(int, Y& meinY , int = 0): _meinY(meinY){};
      X(const X&);
      bool move();
    };
    
    class Y {
    public:
      Y();
      Y( int = 0);
      Y(const Y&, int = 0);
    };
    


  • Garnicht. Referenzen brauchen immer eine Initialisierung. Vermutlich willst du aber keine Referenz speichern, sondern einen Pointer. Den kann man defaultmässig mit 0 initialisieren, um zu signalisieren, dass er auf kein gültiges Objekt zeigt.
    C++ ist kein C#, du begibst dich hier auf dünnes Eis, weil du die komplette Speicherverwaltung und Lebensdauer von Objekten selbst übernehmen musst und dir kein Garbage Collector die Arbeit abnimmt.



  • Es kann hier keine 1:1 Übersetzung geben. Die Sprachen sind dafür zu unterschiedlich. Das ist wie, wenn Du versuchst, einen Wort-Witz zu übersetzten, der nur in der Originalsprache lustig ist. Denk Dir einfach einen anderen Witz aus, der in der Ziel-Sprache funktioniert.

    In Deinem C# Beispiel ist m im Konstruktor von X ein Referenz-Parameter auf eine Referenz (Y ist ja ein Referenztyp). Das scheint Dir nicht klar zu sein; denn Du nutzt dies nirgends aus. Das ref kannst Du getrost weglassen in Deinem C#-Beispiel.

    Du weißt auch, dass class in den zwei Sprachen anders "funktioniert", ja?

    Wie DocShoe schon sagte, in C++ gibt's keine "Garbage Collection". Zur Verwaltung der Lebenszeit von Objekten ordnet man ihnen einen "Besitzer" zu, der für das Löschen verantworklich ist. Diese "Besitzverhältnisse" ergeben typischerweise eine Baumstruktur oder zumindest einen DAG, wenn sich mehrere Objekte den Besitz teilen (zB tr1::shared_ptr) -- mag vielleicht auch Ausnahmen geben...



  • Du kannst durchaus referenzen als Parameter verwenden nur brauchst du dafür die Initialisierungsliste.

    class test
    {
    public:
         test(typ & lala)
          :  ref(lala) // 
         {
         }
    
    private:
         typ & ref;
    }
    

    Die Sache ist halt die, das die Elemente bereits existieren wenn wenn der Konstruktorrumpf aufgerufen wird und da ist es mit der Initialisierung schon zu spät. Zur Initialisierung von Werten brauchst du halt diese Initialiserungsliste.

    EDIT:
    Die Reihenfolge in der Klassen erstellt werden spielt eine Rolle, Bezeichner sind erst dann bekantn wenn sie zuvor schon mal deklariert wurden.
    Um zukünftigen Problemen vorzubeugen (bei sich gegenseitig speichernden Klassen) kannst du ja mal nach Vorwärtsdeklaration schauen.



  • Ich hab das ganze hier nur einmal in C# geschrieben um verständlicher zu machen
    was ich eigentlich will...

    Die Sache ist die, das ganze ist eine Vorgabe von einer Übung.
    Darin steht das eine Klasse zu erstellen ist die folgenden Member hat und dafür
    sind unter anderm die Constructoren zu schreiben:

    //X.h
    Class X{
    private:
      Y& bla_;
    public:
      X(Y& bla);
    };
    
    //X.cpp
    X::X(Y& bla):bla_(bla)
    {}
    

    So funktioniert das ganze ja, nur sobald ich den default Constructor dazu tue
    also X() meckert der Compiler das bla_ natürlich nicht null sein darf.

    Jetzt is die Frage wie kann ich hier trotzdem den default Contructor
    implementieren?



  • Jetzt is die Frage wie kann ich hier trotzdem den default Contructor
    implementieren?

    Wie jeden anderen Konstruktor auch.

    //X.h
    Class X {
    private:
      Y& bla_;
    public:
      X(Y& bla);
      X(); // Default Ctor
    };
    
    //X.cpp
    X::X(Y& bla): bla_(bla) { }
    X::X(): bla_(/*Default-Wert*/) { } // Default Ctor
    


  • Oh, sorry, habe übersehen, dass es sich beim Member Y um eine Referenz handelt.
    Ist dann ein Default Ctor überhaupt sinnvoll?



  • diego2k schrieb:

    Die Sache ist die, das ganze ist eine Vorgabe von einer Übung.

    Aha. Sicher, dass Du eine Referenz als Element haben willst?

    diego2k schrieb:

    Jetzt is die Frage wie kann ich hier trotzdem den default Contructor
    implementieren?

    Auch ein Default-Konstruktor müsste die Referenz bla_ initialisieren. Aber womit?

    Ich habe immer noch das Gefühlt, dass du wichtige C++ Konzepte nicht verstanden hast -- Referenzen zum Beispiel.



  • super danke 🙂
    bla_() auf die Idee hier nichts reinzuschreiben kommt man gar nicht so leicht -.-

    aber jetzt hab ich noch das problem das er mir ein warning ausgiebt:
    default-initialization of 'Y' which has reference type.

    leider darf ich Y.cpp/.h nicht verändern ...



  • diego2k schrieb:

    super danke 🙂
    bla_() auf die Idee hier nichts reinzuschreiben kommt man gar nicht so leicht -.-

    Dann probier mal aus, ob's auch wirklich funktioniert.



  • diego2k schrieb:

    aber jetzt hab ich noch das problem das er mir ein warning ausgiebt:
    default-initialization of 'Y' which has reference type.

    🙄
    Is klar. Referenzen referenzieren immer ein Objekt. Sie müssen dementsprechend initialisiert werden.

    diego2k schrieb:

    leider darf ich Y.cpp/.h nicht verändern ...

    Also entweder hat der, der die Übungsaufgabe gestellt hat, keinen Plan von C++ oder Du hast die Aufgabenstellung nicht richtig wiedergegeben.



  • Also entweder hat der, der die Übungsaufgabe gestellt hat, keinen Plan von C++ oder Du hast die Aufgabenstellung nicht richtig wiedergegeben.

    Ich vermute Letzteres. Wenn Ersteres zutrifft, kannst du ja deinem Konstruktor einen Default Konstruktor mit Speicherleck implementieren:

    X::X(): bla_(*(new Y())) { } // Default Ctor
    

    Glaube aber kaum, dass das die gesuchte Lösung ist.



  • Über sowas macht man keine Witze, Bruder Lustig! 😮

    Also, die einzige Möglichkeit, die ich sehe, die sich auch nur in (sehr) relativer Nähe zur Grenze der geistigen Gesundheit bewegt, ist dafür ein Objekt mit static storage duration vorzuhalten, etwa

    //X.h
    Class X {
    public:
      X(Y& bla);
      X(); // Default Ctor
    
    private:
      Y& bla_;
      static Y default_wert;
    };
    
    //X.cpp
    X::X(Y& bla): bla_(bla) { }
    X::X(): bla_(X::default_wert) { } 
    
    Y X::default_wert;
    

    Die üblichen Vorbehalte gegen globale Variablen halten natürlich auch hier.



  • seldon schrieb:

    Also, die einzige Möglichkeit, die ich sehe, die sich auch nur in (sehr) relativer Nähe zur Grenze der geistigen Gesundheit bewegt, ist dafür ein Objekt mit static storage duration vorzuhalten, etwa

    Da gefällt mir die new variante fast besser...

    und du musst die header datei ändern, was laut aufgabenstellung nicht erlaubt ist.

    was natürlich gehen würde wäre folgendes:

    namespace {
      Y& sodomize() {
        static Y sodomizer;
        return sodomizer;
      }
    }
    X::X(): bla_(sodomize()) { }
    

    dann sind wir innerhalb der aufgabenstellung geblieben... der name der funktion sagt aber schon alles 😕

    PS:
    bei dieser aufgabenstellung gibt es keine tragbare lösung.

    PPS:
    oder eben einen memory manager schreiben:
    der dir ein Y objekt liefert und im dtor von X rufst du halt deleteObjIfExists() auf und wenn der manager das Y objekt erstellt hat, löscht er es.



  • Danke für die Antworten!

    X::X(): bla_(*(new Y())) { } // Default Ctor
    

    also das funktioniert mal ...
    aber Speicherlecks sind nicht das was ich will ....

    Auch die anderen Code Snippets funktionieren. Das Y is eigentlich nur eine
    print Klasse da passiert gar nix außer 2 Methoden die nen char* entgegennehmen und aufm Bildschirm ausgeben.

    Wie wär den das schlauer zu machen?

    wenn ich in der cpp keinen default constructor einbaue sondern nur in der .h
    gibts auch keine warning ... warum?
    allerdings muss ich leider einen char array initialisieren und
    dafür brauch ich den Constructor ....



  • diego2k schrieb:

    X::X(): bla_(*(new Y())) { } // Default Ctor
    

    also das funktioniert mal ...
    aber Speicherlecks sind nicht das was ich will ....

    Dann ist ja gut.

    diego2k schrieb:

    Auch die anderen Code Snippets funktionieren. Das Y is eigentlich nur eine
    print Klasse da passiert gar nix außer 2 Methoden die nen char* entgegennehmen und aufm Bildschirm ausgeben.

    Wie wär den das schlauer zu machen?

    Du bist ja ein Spaßvogel. Zeigst hier zwei Klassen X und Y und fragst, wie's besser geht. Besser wäre natürlich die Klassen A und B zu nennen! 🙄

    Wenn Du etwas konstruktiveres hören willst, musst Du schon mit mehr Infos rausrücken...

    diego2k schrieb:

    wenn ich in der cpp keinen default constructor einbaue sondern nur in der .h
    gibts auch keine warning ... warum?

    Wieso sollte es die geben? Machst ja nix verbotenes, dann. Du kannst den Default-Ctor nur dann nicht aufrufen, weil er nur deklariert und nicht definiert wurde. :p

    diego2k schrieb:

    allerdings muss ich leider einen char array initialisieren und
    dafür brauch ich den Constructor ....

    Was für'n char-Array? Zeig doch mal.



  • wenn ich in der cpp keinen default constructor einbaue sondern nur in der .h
    gibts auch keine warning ... warum?

    Solange nirgends der Standardkonstruktor gebraucht wird, gibt's keinen Fehler.
    Vielleicht könntest du eine globale Instanz dieser Klasse verwenden für den Standardkonstruktor verwenden.

    Ein bisschen Code dieser print-Klasse wäre gut.



  • naja da gibts nicht viel zu sehen:

    //Y.h
    class Y
    {
    private:
      Y(const Y& quelle);
      Y &operator=(const Y& quelle);
    public:
      Y();
      virtual ~Y() throw();
      void print1(const char* a, ...) const;
      void print2(const char* a, ...) const;
    };
    
    //Y.cpp
    Y::Y(){}
    void Y::print1(const char* a, ...) const
    {
      std::cout << a << std::endl;
    }
    void Y::print2(const char* a, ...) const
    {
      std::cout << a << std::endl;
    }
    Y::~Y()throw(){}
    


  • diego2k schrieb:

    naja da gibts nicht viel zu sehen:

    Deine Codes machen alle hinten und vorne keinen Sinn...

    Kannst du mal etwas mehr Code per Copy&Paste posten?



  • diego2k schrieb:

    //Y.h
    class Y
    {
    private:
      X(const X& quelle);
      X &operator=(const X& quelle);
    public:
      X();
      virtual ~X() throw();
      void print1(const char* a, ...) const;
      void print2(const char* a, ...) const;
    };
    

    Mal davon abgesehen, dass Du hier ein paar Xs stehen hast, die Ys hätten sein sollen: Was soll das? Was ist der Sinn dieser Klasse? Warum hat sie keine Datenelemente? Warum hat sie einen virtuellen Destruktor und sonst nichts anderes virtuelles? Wozu ist das gut? Soll das so eine Art "Interface" (im Java-Sinne)? Dann hättest Du vergessen, print1 und print2 pur virtuell zu machen. Dann wären aber auch Deine Deklarationen von copy_ctor und op= überflüssig.

    Wann soll wo wie ein Y erstellt werden, wenn Du den Default-Ctor von X benutzen willst? Und wer soll das Ding wieder löschen?

    So kann man Dir nicht helfen.


Log in to reply