C++: Objekte übergeben



  • Hi und danke für die Antworten!
    Den Hinweis mit Vector werde ich ausprobieren.

    Trotzdem wüsste ich gerne warum bei mir der gepostete Code nicht klappt.
    Das ich ein Array mit Pointern habe ist mir klar.

    return *array_mit_Obj;
    

    sollte einen Pointer auf das 1. Array element zurückgeben und sizeof() sollte dann die Größe des ganzen Arrays zurückgeben...richtig?

    Es sollte doch möglich sein, den Inhalt dieses Arrays in ein Memberarray einer anderen Klasse zu kopieren?
    So wie es jetzt da steht, kann ich immerhin in der Klasse C auf das 1. Objekt im Array zugreifen, der Rest wird aber anscheinend nicht übergeben. Möglicherweise fehlt da irgendwo ein "[]", ich hab aber schon etliche Kombinationen ausprobiert 😞
    Ein kleiner Hinweis, wie ich den Code zum Laufen bringen kann wäre zum Verständnis toll.

    (mit

    A Obj_a();
    

    soll der Konstruktor aufgerufen werden, im echten Programm mit Parametern)
    )
    lg



  • moon12 schrieb:

    Das ich ein Array mit Pointern habe ist mir klar.

    return *array_mit_Obj;
    

    sollte einen Pointer auf das 1. Array element zurückgeben

    Was passiert, wenn du ein Array dereferenzierst, also was gibt folgendes zurück

    int a[5] = {1,2,3,4,5};
    auto x = *a; //welchen Typ und Wert hat x?
    
    SomeType b[5] /* = ...*/;
    auto y = *b; //welche Typ und Wert hat y?
    
    Something* c[5] /* = ...*/;
    auto z = *c; //welche Typ und Wert hat z?
    

  • Mod

    moon12 schrieb:

    Das ich ein Array mit Pointern habe ist mir klar.

    return *array_mit_Obj;
    

    sollte einen Pointer auf das 1. Array element zurückgeben und sizeof() sollte dann die Größe des ganzen Arrays zurückgeben...richtig?

    Weder noch. Arrays haben Sonderregeln und verhalten sich anders als alle anderen Objekte. Wenn du unbedingt Arrays benutzen willst, dann guck dir ein Lehrbuch dazu an. Das ist dann aber eher C-Stil, in C++ würdest du wie gesagt einen STL-Container benutzen, z.B. std::array (Feste Größe) oder std::vector (variable Größe) oder ganz einen anderen (wenn du andere Anforderungen hast). Die verhalten sich dann auch so, wie du intuitiv erwarten würdest.

    Es sollte doch möglich sein, den Inhalt dieses Arrays in ein Memberarray einer anderen Klasse zu kopieren?

    Jain. Aber nicht so einfach. Arrays kopieren ist in C (und damit auch C++) keine Zuweisung. Im Prinzip muss man jedes Element einzeln kopieren. Oder den Containertipp befolgen.

    So wie es jetzt da steht, kann ich immerhin in der Klasse C auf das 1. Objekt im Array zugreifen, der Rest wird aber anscheinend nicht übergeben. Möglicherweise fehlt da irgendwo ein "[]", ich hab aber schon etliche Kombinationen ausprobiert 😞

    In der Programmierung ist Ausprobieren oft eine schlechte Technik. Du musst genau wissen, was jedes einzelne Zeichen in deinem Programm tut und warum du es gesetzt hast. Wie gesagt, wenn du unbedingt Arrays möchtest (dafür gibt es hier jedoch keinen ersichtlichen Grund), dann guck dir zuerst die Sonderregeln dafür an.

    Ein kleiner Hinweis, wie ich den Code zum Laufen bringen kann wäre zum Verständnis toll.

    Ich weiß nicht. Dann übernimmst du diesen Code, redest dir selber ein, dass du es verstanden hast und guckst dir dann die Standardcontainer (die die eigentlich richtige Lösung wären) gar nicht an. Nicht gegen dich, aber das ist einfach Erfahrung, dass das so läuft.



  • int a[5] = {1,2,3,4,5}; 
    auto x = *a; //welchen Typ und Wert hat x?
    
    SomeType b[5] /* = ...*/;
    auto y = *b; //welche Typ und Wert hat y?
    

    Der Typ ist der Elementtyp des Arrays, der Wert ist der des ersten Elements.

    Wieso? Dank dem array-to-pointer decay. a zerfällt in einen Zeiger auf das erste Element und der wird dereferenziert. Das Ergebnis erklärt sich dann von selbst.

    Übrigens lauern bei den echten Arrays Tücken, die man nur durch leidige Selbsterfahrung herausfindet (oder in dem man seine Zeit mit einem guten C++-Buch verbringt, ich empfehle den Primer).
    Daher auch die ganzen Vorschläge zu std::vector und Konsorten.

    Something* c[5] /* = ...*/;
    auto z = *c; //welche Typ und Wert hat z?
    

    dito. Tricky ist hier höchstens, dass in der Deklaration ein Zeiger auftaucht, aber für solche Sachen gibt es cdecl.org.

    In der Programmierung ist Ausprobieren oft eine schlechte Technik.

    Das schlimmste dabei ist auch noch, wenn es durch ausprobieren auf einmal funktioniert... 😃
    Denn dann verstecken sich, gerade wenn man den Code nicht verstanden hat, z. T. Bugs darin...


  • Mod

    Ich glaube, pumuckl hat diese Fragen nicht gestellt, damit du zeigen kannst, dass du Arrays verstehst. Das glauben wir dir auch so.



  • SeppJ schrieb:

    Ich glaube, pumuckl hat diese Fragen nicht gestellt, damit du zeigen kannst, dass du Arrays verstehst. Das glauben wir dir auch so.

    Nein, das war für den TE, weil er sich sowieso nicht die Mühe macht, die Fragen zu recherchieren oder sich damit auseinanderzusetzen.

    Kannst es ja rauseditieren wenn du anderer Meinung bist. 🙂



  • Eigentlich ist schon alles gesagt, aber ich finde Sones Unterstellung unter aller Kanone und wollte nicht, dass die den Abschluss dieses Threads bildet...

    moon12 schrieb:

    Ein kleiner Hinweis, wie ich den Code zum Laufen bringen kann wäre zum Verständnis toll.

    Warum versuchst Du nicht erstmal eine Variante ohne Pointer. Also

    class A{
      B array_von_obj[5];
      //...
    };
    

    Dann wird einiges einfacher.
    Dann merk Dir, dass wenn Du arrays Übergibst diese zu einem Pointer auf das erste Element zerfallen. D.h. dass Array oben wird als B* übergeben - ohne Längeninformation! Die musst Du in einem zweiten Parameter mitschicken.
    D.h. Cs C'tor koennte so aussehen:

    class C{
      public:
        C(B*, size_t);
      //...
    };
    

    Wenn Du das alles hast und willst es dann mit Pointern versuchen: soll C eine Kopie der Pointer vorhalten, oder Pointer auf neue Objekte? Wer gibt den allozierten Speicher wieder frei?



  • @Sone:
    Das möchte ich dezent zurückweisen 🙂 Ich verstehe, dass eure Erfahrungen einschlägig sein mögen, ich habe aber z.B. in der Tat die geposteten Fragen zu beantworten versucht, nur war ich lange nicht so schnell wie Du ^^ Trotzdem Danke!

    Ich habe mir ein Konstrukt mit Vektoren gebaut und übergebe diese "by value", mit der Überlegung, die Klasse, die übergibt, vll später löschen zu können und alles als member in der annehmenden Klasse zu haben...
    Um Kritik zum Code wäre ich dankbar:

    #include<vector>
    #include"B.h"
    
    class A
    {
        vector<B> myBvector;
        vector<B> myAfunction()
        {
            for(...)
            myBvector.push_back(B(...));
            return myBvector;
        }
    };
    
    class B {};
    
    #include<vector>
    #include"B.h"
    
    class C
    {
        vector<B> newvector;
        C(vector<B>);
    };
    
    C::C(vector<B> fromA)
    {
        newvector = fromA;
    }
    
    int main()
    {
    A a();
    C c(a.myAfunction() );
    return 0;
    }
    

    Das ganze kann ich fehlerfrei kompillieren und liefert soweit ich das abschätzen kann, genau was ich wollte
    gruß, moon


  • Mod

    Sieht ok aus, guck dir aber noch dringend einmal an, was eine Initialisierungsliste ist.

    Wenn du noch Zuckerguss draufmachen möchtest: In C++ legt man sich bei Funktionsparametern ungern auf Containertypen fest. Stattdessen übergibt man (templatisierte) Iteratoren auf Anfang und Ende. Damit kann man beliebige Arten von Daten an C übergeben, nicht bloß vectoren. Und es entfällt eine unnötige, teure Kopie, von der ich mir gerade nicht sicher bin, ob sie wegoptimiert werden kann.
    Also zusammenfassend:

    template<typename Iterator> C(Iterator begin, Iterator end): newvector(begin, end) {}
    


  • stimmt etwas mit meinen Initialisierungen nicht?
    bei "..." steht natürlich in echt was anderes. Oder ist die Objektinstanziierung von a mit einem Funktionsaufruf als Paramter unschön?



  • moon12 schrieb:

    stimmt etwas mit meinen Initialisierungen nicht?

    Es tut schon stimmen.

    Aber es geht halt noch viel besser, und deswegen solltest du dir Initialisierungslisten anschaun'.

    @SeppJ: Sind Templates/Iteratorenmodell nicht ein wenig zu weit gegriffen?



  • stimmt wohl, ich hab zwar schon einiges zur Templateprogrammierung gelesen, aber das ist auf jeden Fall noch zu hoch. Ich denke ich machs mir einfacher, wenn ich das erstmal weglasse.

    noch eine Frage:
    Gehe ich richtig in der Annahme, dass der Speicher bei Programmende automatisch freigegeben wird und damit auch die im Vektor gespeicherten Elemente ?!
    D.h. ich muss nicht extra die Objekte im Vektor löschen (erase / delete)?


  • Mod

    Sone schrieb:

    @SeppJ: Sind Templates/Iteratorenmodell nicht ein wenig zu weit gegriffen?

    Ja, aber man kann ja mal einen Ausblick geben. Im Moment fehlt nur die Initialisierungsliste, damit es "ok" ist.

    moon12 schrieb:

    noch eine Frage:
    Gehe ich richtig in der Annahme, dass der Speicher bei Programmende automatisch freigegeben wird und damit auch die im Vektor gespeicherten Elemente ?!

    Jain. Automatisch freigegeben: Ja. Aber nicht zum Programmende, sondern dann, wenn der Vector aus dem Scope (Gültigkeitsbereich) geht.



  • moon12 schrieb:

    stimmt etwas mit meinen Initialisierungen nicht?

    Es stimmt in sofern nicht, das es keine Initialisierungen, sondern nachträgliche Zuweisungen sind. Im Konstruktorrumpf existieren die Werte bereits. Die einzige Stelle beim Konstruktor an der man Initialisieren kann ist die Initialisierungsliste.

    Das mag bei integralen Datentypen unproblematisch sein, bei Objekten rufst du so statt einen Konstruktor in der Regel 2 Konstruktoren und ein Zuweisungsoperator auf (was bei vielen und großen Objekten durchaus Unterschiede machen kann). Zudem kann man Referenzen und Konstanten als Membervariablen ausschließlich in der Initialisierungsliste setzen. Ebenso erzwingst du Standardkonstruktoren bei Objekten.

    class A {} // <-- Irgendein komplexes Element.
    
    class B
    {
      private:
        A a;
    
      public:
        // Fall 1: Ohne Initialisierungsliste.
        B()
        { // <-- Hier wird der Standardkonstruktor von a aufgerufen.
            a = A(123); // <-- Zuweisungsoperator + weiterer Konstruktoraufruf
        }
    
        // Fall 2: Mit Initialisierungsliste
        B()
        : a(123) // <-- Ein Konstruktoraufruf, zudem auch anderer als Standardkonstruktor möglich
        {
        }
    };
    


  • asc schrieb:

    a = A(123); // <-- Zuweisungsoperator + weiterer Konstruktoraufruf
    

    Das mit dem weiteren Konstruktoraufruf bezweifle ich. Die Temporary darf hier doch elidiert werden, oder nicht?

    Edit: Hmm, kann sein, dass das nur der Fall ist wenn ein entsprechender Ctor vorhanden ist...



  • Sone schrieb:

    asc schrieb:

    a = A(123); // <-- Zuweisungsoperator + weiterer Konstruktoraufruf
    

    Das mit dem weiteren Konstruktoraufruf bezweifle ich. Die Temporary darf hier doch elidiert werden, oder nicht?

    • Grundsätzlich gehe ich niemals von Compileroptimierungen bei Beschreibungen aus. Wenn diese greifen, schön und gut, aber zu wissen was im schlechten Fall passieren kann ist etwas anderes.
    • Kann ich mir das hier nicht ganz vorstellen (außer vielleicht durch C++11, da ich mich mit Movesemantik etc. noch nicht großartig beschäftigt habe - beruflich wäre ich froh wenn der verwendete Compiler schon mit dem Standard davor weitgehend kompatibel wäre [Ins Besondere bei Templates]).


  • asc schrieb:

    Sone schrieb:

    asc schrieb:

    a = A(123); // <-- Zuweisungsoperator + weiterer Konstruktoraufruf
    

    Das mit dem weiteren Konstruktoraufruf bezweifle ich. Die Temporary darf hier doch elidiert werden, oder nicht?

    • Grundsätzlich gehe ich niemals von Compileroptimierungen bei Beschreibungen aus. Wenn diese greifen, schön und gut, aber zu wissen was im schlechten Fall passieren kann ist etwas anderes.
    • Kann ich mir das hier nicht ganz vorstellen (außer vielleicht durch C++11, da ich mich mit Movesemantik etc. noch nicht großartig beschäftigt habe - beruflich wäre ich froh wenn der verwendete Compiler schon mit dem Standard davor weitgehend kompatibel wäre [Ins Besondere bei Templates]).

    😃


Anmelden zum Antworten