Konstruktor eines VectorObjekts



  • Hallo,

    ich stelle mich gerade mal wieder bloed an, darum muss ich euch mit meiner Frage belaestigen.

    Ich habe eine Klasse

    class myClass {
      public:
        const double a, b;
    
        // Konstruktor
        myClass(double aa, double bb) : a(aa), b(bb) {}
    };
    

    und will dann einen Vektor-Objekt mit Typ myClass erschaffen. Probleme bekomme ich dann, wenn ich die Membervariablen der Objekte ueber den Konstruktor initialisieren will.

    #include <vector>
    
    using namespace std;
    
    int main(int argc, char **argv)
    {
      vector<myClass> vecObj;
      vecObj.resize(3);
    
      for(unsigned i=0; i < vecObj.size(); ++i) {
        vecObj[i](i*1.0, i*2.0);
      }
    
      return 0;
    }
    

    Der Compiler spuckt mir folgendes aus.

    > g++ test_vecObj.cc -o test -Wall - pedantic
    test_vecObj.cc: In function 'int main(int, char**)':
    test_vecObj.cc:19: error: no match for call to '(myClass) (double, double)'
    /usr/lib/gcc/x86_64-mandriva-linux-gnu/4.0.1/../../../../include/c++/4.0.1/bits/stl_vector.h: In member function 'void std::vector<_Tp, _Alloc>::resize(size_t) [with _Tp = myClass, _Alloc = std::allocator<myClass>]':
    test_vecObj.cc:16:   instantiated from here
    /usr/lib/gcc/x86_64-mandriva-linux-gnu/4.0.1/../../../../include/c++/4.0.1/bits/stl_vector.h:442: error: no matching function for call to 'myClass::myClass()'
    test_vecObj.cc:10: note: candidates are: myClass::myClass(double, double)
    test_vecObj.cc:5: note:                 myClass::myClass(const myClass&)
    

    Offensichtlich muss ich das irgendwie anders machen. Ich habe schon mal geguckt, wie ein normaler Vektor initialisiert werden kann:

    vector( size_type num, const TYPE& val = TYPE() );
    vector( input_iterator start, input_iterator end );
    

    Das erste passt nicht, da die Membervariablen immer unterschiedliche Werte bekommen sollen.
    Beim 2. bin ich mir nicht so sicher, wie das funktioniert.

    Vielen Dank schon mal,
    HarryKane



  • Ahh, ein Klassiker (FAQ-Kandidat ?):

    harrykane schrieb:

    ...

    ...
      vecObj.resize(3);
    ...
    

    Schonmal drüber nachgedacht, was diese Zeile machen soll ?
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    -> sie soll 3 myClass-Objekte erzeugen.
    Und wie ?
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    -> mit dem Standardkonstruktor. Und wo ist der ?
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    .
    -> Nicht implementiert und - da Du einen (double,double)-Ctor definiert hast - nicht vom Compiler automatisch bereitgestellt. 😉

    Das sagt auch die Fehlermeldung:

    no matching function for call to 'myClass::myClass()

    Gruß,

    Simon2.


  • Administrator

    Ehm, es hat allerdings noch ein Fehler drin 😉
    Und zwar dieser hier:

    test_vecObj.cc:19: error: no match for call to '(myClass) (double, double)'

    An dieser Stelle:

    for(unsigned i=0; i < vecObj.size(); ++i)
    {
        vecObj[i](i*1.0, i*2.0);
    }
    

    Weisst du was du da machst? Du holst dir eine Reference zum Objekt und rufst darauf den operator ()(double, double) auf. Nix Konstruktor 🙂
    Es ist halt eben wie Simon2 schon gesagt hat. Das Objekt wird viel früher erstellt.

    Grüssli



  • Ok, soweit so gut. Aber wie erstelle ich denn nun die Objekte des Vektors mit dem Konstruktor richtig???



  • harrykane schrieb:

    Ok, soweit so gut. Aber wie erstelle ich denn nun die Objekte des Vektors mit dem Konstruktor richtig???

    int main()
    {
      vector<myClass> vecObj;
    
      for(unsigned i=0; i<3; ++i)
        vecObj.push_back(myClass(i*1.0, i*2.0));
    }
    

    cu André



  • asc schrieb:

    int main()
    {
      vector<myClass> vecObj;
     
      for(unsigned i=0; i<3; ++i)
        vecObj.push_back(myClass(i*1.0, i*2.0));
    }
    

    cu André

    Hmm, guter Versuch. Auf die push_back variante bin ich auch gerade gestossen. Doch er stoesst sich wohl daran dass die Variablen const sind. (Ohne const laufts aber)

    test_vecObj.cc: In member function 'myClass& myClass::operator=(const myClass&)':
    test_vecObj.cc:5:   instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = myClass, _Alloc = std::allocator<myClass>]'
    /usr/lib/gcc/x86_64-mandriva-linux-gnu/4.0.1/../../../../include/c++/4.0.1/bits/stl_vector.h:610:   instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = myClass, _Alloc = std::allocator<myClass>]'
    test_vecObj.cc:19:   instantiated from here
    test_vecObj.cc:5: error: non-static const member 'const double myClass::a', can't use default assignment operator
    test_vecObj.cc:5: error: non-static const member 'const double myClass::b', can't use default assignment operator
    /usr/lib/gcc/x86_64-mandriva-linux-gnu/4.0.1/../../../../include/c++/4.0.1/bits/vector.tcc: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = myClass, _Alloc = std::allocator<myClass>]':
    /usr/lib/gcc/x86_64-mandriva-linux-gnu/4.0.1/../../../../include/c++/4.0.1/bits/vector.tcc:260: warning: synthesized method 'myClass& myClass::operator=(const myClass&)' first required here
    

    PS: Mal ne kleine Frage am Rande, warum wird manchmal der CODE mit und manchmal ohne Zeilennummer ausgegeben??



  • harrykane schrieb:

    Hmm, guter Versuch. Auf die push_back variante bin ich auch gerade gestossen. Doch er stoesst sich wohl daran dass die Variablen const sind. (Ohne const laufts aber)

    Das liegt an den allgemeinen Anforderungen der Containerklasse zu Objekten. Eine andere Möglichkeit wäre mit Zeigern oder Smartpointern (wie boost::shared_ptr) zu haben (inkl. allen damit verbundenen Nachteilen).

    harrykane schrieb:

    PS: Mal ne kleine Frage am Rande, warum wird manchmal der CODE mit und manchmal ohne Zeilennummer ausgegeben??

    Das hat mit der Anzahl der Zeilen zu tun. Ab einer bestimmten Anzahl macht er es (Für Code aber bitte die C/C++ Tags nehmen).

    cu André



  • harrykane schrieb:

    ...Doch er stoesst sich wohl daran dass die Variablen const sind. (Ohne const laufts aber)...

    Das ist ein allgemeines Problem bei der Nutzung "unkopierbarer Klassen" (const oder Referenzen oder nicht verfügbarer CopyCtor oder ...) mit einigen Standardcontainern: Da vector die Objekte bisweilen kopieren muss (z.B. wenn neuer Speicher allokiert werden muss), gibt's dann Ärger.
    Und wenn ich das richtig sehe, wird im push_back()-Beispiel auch ein Objekt kopiert...
    Kann sein, dass std::list das Problem nicht hat.

    harrykane schrieb:

    ...
    PS: Mal ne kleine Frage am Rande, warum wird manchmal der CODE mit und manchmal ohne Zeilennummer ausgegeben??

    Hat mich auch mal gewundert und ist ganz banal ... ab 8 (?) Zeilen wird numeriert.

    Gruß,

    Simon2.



  • Och menno, das ist doch jetzt doof. Dann haette ich mir die ganze Arbeit auch sparen koennen *grml*. Naja, immerhin wieder etwas gelernt. Vllt gucke ich mir dann noch mal std::list an.

    Jedenfalls, vielen Dank fuer eure prompte Hilfe.

    Gruss,
    HarryKane



  • Brauchst Du denn wirklich, dass die Member const sind ?
    Wenn sie private sind, kommt doch sowieso niemand an sie heran...

    Gruß,

    Simon2.



  • Sie sind aber public. Stellt sich natuerlich die Frage, "warum stelle ich sie auch public und nicht privat". Die Antwort ist schlicht und einfach: ich wollte mir Schreibarbeit ersparen und nicht noch zusaetzliche Funktionen basteln (und benutzen muessen) um auf die Variablen zuzugreifen bzw. zu schreiben.

    Das Problem ist inzwischen, dass urspruenglich nur mit einem Objekt gearbeitet wurde (da hatte das mit dem const ja auch wunderbar funktioniert). Nun ist aber die Notwendigkeit entstanden beliebig viele Objekte zu benutzen, also musste ich sie in einen Vektor packen. Was dann halt nur nicht so toll funktioniert hat, wie ich mir das gewuenscht haette.

    Im Nachhinein noch alles mit privat Variablen zu schreiben waere nen ganz schoener Aufwand. Ich gucke gerade wieviel Arbeit es machen wuerde auf Listen umzusteigen.



  • harrykane schrieb:

    Die Antwort ist schlicht und einfach: ich wollte mir Schreibarbeit ersparen und nicht noch zusaetzliche Funktionen basteln (und benutzen muessen) um auf die Variablen zuzugreifen bzw. zu schreiben.

    Faulheit hilft niemanden und macht Design auch nicht besser. Wenn ich bedenke wieviel Fehlersuche ich schon betreiben musste, wegen jemanden der, weil es "einfacher" war alle Variablen öffentlich publiziert hatte, dann kann ich nur sagen: Faulheit rentiert sich nicht.

    cu André


Anmelden zum Antworten