Vektoren als Klassenattribute


  • Mod

    Oje, noch ein Opfer 🙄 . Das sind aber ganz schön viele heute. Was ich damit meine. Alternativen.

    Zu deiner eigentlichen Frage: Dynamsiche Speicherverwaltung ist hier völlig unangebracht. Was du brauchst ist eine Initialisierungsliste (mal nach googeln).



  • du deklarierst einen member sequences als std::vector<std::string> und weist dem im Konstruktor einen pointer auf std::vector<std::string> zu .. das kann nicht gehen. Vergiß new 🙂 und this-> ist auch seltenst nötig, am besten auch vergessen 😉

    class X 
    {
      std::vector<std::string> sequences;
    public:
      X();
    };
    
    X:X() 
    {
    // sequences ist kein pointer also nix new ... der ist schon fertig initialisiert. wenn du abschätzen kannst wieviele Strings du speichern willst kannste noch sequences.reserve(anzahl) machen ...
    sequences.reserve(20); // macht den so groß das 20 strings rein passen würden /(ist aus anderen Gründen hier dünnsinn aber egal)
    std::cout << sequences.size();
    sequences.push_back("ich"); std::cout << sequences.size() << std::endl;
    sequences.push_back("will"); std::cout << sequences.size() << std::endl;
    sequences.push_back("aber"); std::cout << sequences.size() << std::endl;
    sequences.push_back("nicht"); std::cout << sequences.size() << std::endl;
    sequences.push_back("!"); std::cout << sequences.size() << std::endl;
    for(int i=0; i<sequences.size(); ++i) std::cout << sequences[i] << "\t";
    std::cout << std::endl
    sequences.clear();std::cout << sequences.size() << std::endl;
    
    }
    

    Prizipiel::

    std::string   kp = "5";                      // kein pointer
     std::string * pp = new std::string("hallo"); // pointer
    
     std::cout << kp.size(); // member von "kein pointer" über .
     std::cout << pp->size(); // member von "pointer" über ->
    
     std::cout << (*pp).size(); // dereferenzierter pointer ... google ;)
    
     delete pp; // pointer muss man immer wieder aufräumen !
    


  • Danke für den vielen Input, ich habe da nun einiges drüber nachgedacht. Kann mir noch einer sagen, wie die getter- und setter bei den Attributen mit den vector-Listen heißen müssen?



  • Jay1980 schrieb:

    Danke für den vielen Input, ich habe da nun einiges drüber nachgedacht. Kann mir noch einer sagen, wie die getter- und setter bei den Attributen mit den vector-Listen heißen müssen?

    Welche getter und setter? Mach die nur, wenn es sinnvoll ist, und das ist es bei vector-Attributen eigentlich nie.



  • In dem Fall denke ich werde ich die sicher brauchen. Das Attribut im Header-File heisst vector<string> sequences aus der Klasse Msa, nun brauche ich die Methoden getSequences und setSequences ... wie müssen die aussehen? Das klappt bis jetzt noch nicht so.



  • Stelle dir mal folgende Frage: Was sind das denn für Sequenzen?

    Dann wirst du evtl. feststellen, das du keine Vectoren zurück geben mußt. Der Vector ist ein Implementierungs-Detail, welches man vor dem Anwender der Klasse verstecken kann bzw. sollte. Dadurch kannst du später z.B. auf eine Liste umsteigen (aus welchen Gründen auch immer), ohne das der Anwender seinen Code anpassen muß. Oder ihm eine ganz andere Sequenz in Sonderfällen zurück geben.

    Also, was ist der Sinn der Sequenzen? Welchen fachlichen Hintergrund haben sie?

    Einen vector<string> würde ich in einem setter/Getter nur als Convinience-Funktionen machen. Also unabhängig von der Implementierung.



  • Okay,
    ich überlege es mir später gern es anders zu machen, ist aber jetzt einer in der Lage und hat die Muße mir die setter- und getter-Methode einmal auszuformulieren.
    Es ist so: der Algorithmus, den ich in Java schon implementiert habe, läuft und da wird viel mit ArrayList<String> gearbeitet oder ArrayList<Sequence>, wenn ich die Liste mit einem der zahlreichen Hilfsobjekte bestücke - ich möchte also unbedingt wissen, wie man Accessormethoden für Listen in C++ erstellt.

    Zu den Sequenzen: es geht um ein Multiples Sequenz Alignment, ein Bündel von Strings, die zueinander ausgerichtet werden. Dann werden weitere Listen angelegt, etwa eine Liste aus den Strings pro Spalte. Es ist also wie eine Matrix. Ich kann aber vorher nicht wissen wieviel Sequenzen und wie lange sie sind, die Wahl eines Containers fand ich geeignet, in Java macht man das wohl auch so.



  • Vermutlich so:

    // 1.
    const std::vector<std::string> & getSequence() const { return &sequence; }  // nicht änderbare referenz auf deins
    // 2.
          std::vector<std::string>   getSequence()       { return  sequence; }  // kopie von deinem
    // 3.
    std::string sequences() // komma separierte liste von gefundenen Sequenzen
    {
      std::string erg;
    
      for(int i=0; i < sequence.size(); ++i) { erg.append(sequence[i]+","); }
    
      erg.resize(erg.size()-1); // delete last ','
    
      return erg;
    }
    

    Letzteres würde das Ergebnis unabhängig von der von dir verwendeten Datenhaltung machen ... änderst du std::vector->std::list wäre das für den Nutzer im 3. Fall egal, im 2. Fall könntest du deine Exportmethode so umschreiben das sie die Liste in nen Vektor stopft und den zurückgibt ... im ersten Fall würde der User seinen Code umbauen müssen (oder du musst richtig unsauber hacken, damit das noch tut).



  • Hier mal meine beiden Klassen:
    multisequencealignment.cpp

    #include <iostream>
    #include <string>
    #include <vector>
    #include "multiplesequencealignment.h"
    
    using namespace std;
    
    // Konstruktor, Wolf S. 286
    MultipleSequenceAlignment::MultipleSequenceAlignment(){
    
    	cout << "MultipleSequenceAlignment-Instanz erzeugt!\n";
    
    	string str( "Konstruktorstandardname" );
    	this->setName( str );
    
    	// TODO passende Laenge ermitteln Wolf S. 325
    	sequences.reserve(5);
    	columnsStrings.reserve(5);
    }
    
    // Destruktor
    MultipleSequenceAlignment::~MultipleSequenceAlignment(void){
    	cout << "... Destruktor MultipleSequenceAlignment-Instanz aufgerufen!\n";
    }
    
    // Accessors
    string& MultipleSequenceAlignment::getName(void){ // cbr durch Referenzen nachbilden, Wolf S. 184
    	return this->name;
    }
    void MultipleSequenceAlignment::setName(const string& name){
    	this->name = name;
    }
    
    vector<string> getSequences( void ){
    	return sequences;
    }
    
    void setSequences( vector<string> sequencesVector ){
    	this->sequences = sequencesVector;
    }
    
    // Debugging
    string MultipleSequenceAlignment::toString( void ){
    	string str;
    	str.append( "MulitpleSequenceAlignment-Instanz.toString: ");
    	str.append( "Name: " + name );
    	str.append( "\n" );
    	return str;
    }
    

    Und hier multisequencealignment.h:

    #ifndef MULTIPLESEQUENCEALIGNMENT_H_
    #define MULTIPLESEQUENCEALIGNMENT_H_
    
    #include <string>
    #include <vector>
    
    using namespace std;
    
    class MultipleSequenceAlignment{
    private:
    	// Attribute
    	string name;
    	vector<string> sequences; // vector, Wolf S. 533f
    	vector<string> columnsStrings;
    
    	// private Methoden
    	// -
    
    public:
    	// Konstruktor Wolf S. 544
    	MultipleSequenceAlignment(); // Methodenrumpf hier, dann haben wir eine inline-Funktion
    
    	// Destruktor Wolf S. 544
    	~MultipleSequenceAlignment();
    
    	// Accessors
    	string& getName(void);
    	void setName(const string& str);
    
    	vector<string> getSequences( void );
    	void setSequences( vector<string> sequences );
    
    	vector<string> getColumnsStrings( void );
    	void setColumnsStrings( vector<string> columnsStrings );
    
    	// Debugging
    	string toString( void ); // Instanzmethode, in Source-File gerumpft
    
    };
    
    #endif /* MULTIPLESEQUENCEALIGNMENT_H_ */
    

    In obiger Version im cpp-File erhalte ich Kompilierfehler, da 'sequences' not declared ist. Das verstehe ich nicht, denn bei name ging das ja auch, dass ich darauf zugreifen kann - was mache ich falsch, was habe ich übersehen?

    Das kostet mir bis jetzt viel Zeit und danke an alle, die sich immer noch überwinden können, mir mit dem ein oder anderen Codeschnippsel/Tipp zu helfen.

    PS.: ich will das unbedingt verstehen, in Java hatte ich auch mal so einen Zeitfresser, da war mir nicht klar, dass man Container in jedem Fall als Attribut initialisieren muss und bei normalen Variablen übernimmt das Java selbst - vielleicht gibt es ja hier auch so einen 'Unterschied'.



  • Du hast das MultipleSequenceAlignment:: vor den Funktionsnamen vergessen.



  • nimm mal das using namespace std; aus dem Header raus. Als generelle Regel, qualifizier in den .h's selbst, in der cpp kann man die using nutzen
    und this-> brauchst du in der cpp nicht ... durch das qualifizieren der Methoden (was du eben vergessen hast bei den settern) ist ein implizites this-> gegeben


Anmelden zum Antworten