C++ Vektor einer Klasse ausgeben

Dosenfutter123

Cadet 1st Year
Registriert
Mai 2016
Beiträge
14
Guten Abend,

als ziemlicher Anfänger, was Programmieren in der Sprache C++ angeht, wage ich mich derzeit an Vektoren. Im derzeitigen Programm will ich eine Art Schulverwaltung anlegen, in welcher ich verschiedene Personen/Schüler speichern kann. Die Schüler möchte ich jetzt in einer Gruppe zusammenfassen. Jedoch weiß ich nicht, wie ich es schaffe den Vektor der Gruppe wieder auszugeben oder ob es mit meinem Gedankengang überhaupt möglich ist, so die einzelnen Personen wieder auszugeben.

Folgenden Code habe ich bereits geschrieben:

Code:
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::cin;
using std::string;


class Person
{
   private:
   string Geschlecht;
   string Name;
   float Abschluss;
   std::vector<Person> Gruppe;

   public:
   void add();
   void ausg();
   void addgroup(Person pe);
   void printgroup();
};

void Person::add ()
{
  string name;
  string geschlecht;
  float note;

  std::cout << "Bitte Anrede eingeben: " << std::endl;
  std::cin >> geschlecht;
  std::cout << "Bitte Nachname eingeben: " << std::endl;
  std::cin >> name;
  std::cout << "Bitte Abschluss eingeben: " << std::endl;
  std::cin >> note;

  Geschlecht = geschlecht;
  Name = name;
  Abschluss = note;
}


void Person::addgroup(Person pe1)
{
  Gruppe.push_back(pe1);
}

void Person::printgroup()
{
}

void Person::ausg()
{
  std::cout << "Person: " << Geschlecht << " " << Name << " ,Note: " << Abschluss << std::endl;
}

int main()
{
  Person pers1;
  Person pers2;
  Person gruppe1;

  pers1.add();
  pers1.ausg();
  pers2.add();
  pers2.ausg();


  gruppe1.addgroup(pers1);
  gruppe1.addgroup(pers2);
  gruppe1.printgroup();
}

Wenn dieser soweit aktzeptabel ist, wäre es interessant, wie ich am einfachsten meine printgroup()-Funktion gestalte. Mein Einfall wäre gewesen eine Variable (z.B. i) anzulegen welche iteriert wird. In der Funktion hätte ich einfach mit std::cout << Gruppe->Name die einzelnen Namen ausgegeben. Dies scheint aber so nicht zu funktionieren.
Bei Tipps und Hilfen wäre ich sehr dankbar.

Mit freundlichen Güßen
 
Zu deiner eigentlichen Frage:
Natürlich ist es möglich, warum denn auch nicht? Wenn du C++11 nimmst kannst du mit foreach Syntax über deinen Vektor iterieren, sieht dann zB so aus:
Code:
for( Person person : Gruppe )
{
    person.ausg(); // Oder wie auch immer du das geprintet haben willst
}
Alternativ genau wie du es machen wolltest:
Code:
for( size_t i = 0; i < Gruppe.size(); ++i )
{
    Gruppe[i].ausg(); // Oder wie auch immer du willst
}

Zu deinem Code noch, versuch dich an gängige Coding Conventions zu halten, auch wenn du nicht musst und dir natürlich absolut frei steht wie du deinen Code schreiben willst.
Also zB benenne Variablen mit lower-case. Schreibe deinen Code auf Englisch, rücke Labels nach links. Wenn du using verwendest, dann verwende es auch und schreib nicht die ganze Zeit std::cout und so, wenn du eh using std::cout stehen hast.

Dann noch zur Struktur deines Codes, es ist nicht sehr sinnvoll innerhalb der add() Methode die Eingabe zu machen. Normalerweise sollte die Person Klasse nur die Möglichkeit bieten Personen zu speichern, die Eingabe sollte außerhalb der Klasse passieren. Weil wenn du jetzt eine Person hinzufügen willst, die du aber nicht von der Standardeingabe liest, sondern zB aus einer Datei, wie bekommst du sie dann in deine Klasse?
Dann kannst du dir noch überlegen, ob es nicht sinnvoller wäre, deine Gruppe als eigene Klasse zu definieren. Weil so wie du es jetzt hast, kann eine Person eine beliebige Gruppe an Personen beinhalten, diese Personen in der Gruppe können dann wieder Gruppen von Personen haben und so weiter. Außerdem weiß eine Person nicht ob sie in einer Gruppe von einer anderen Person ist und noch ein paar andere Nachteile.

Gruß
BlackMark
 
Frage zurück, warum i++ und nicht ++i?
Also im Prinzip ist es total egal, theoretisch ist ein i++ langsamer, weil es eine temporäre Variable anlegen muss um den Wert vor der Inkrementierung zu speichern, das wird aber ziemlich sicher vom Compiler wegoptimiert und am Ende sollten genau die gleichen Assembly Instructions raus kommen. Ich habe mir halt angewöhnt ++i zu schreiben, weil das eher meiner Intention entspricht. Ich will ja die Variable i um eines erhöhen, mir ist egal ob der Ausdruck zu i oder zu i+1 evaluiert wird, solange i danach um 1 größer ist. Ich verwende i++ nur dann, wenn ich wirklich will, dass der Ausdruck zu i evaluiert und danach erst um eines erhöht wird.

Gruß
BlackMark
 
i++, einerseits aus Gewohnheit, weil ich den Postinkrementor öfter brauche und andererseits sieht mans fast überall so ;)
danke! Der theoretische Performance Unterschied war mir vorher gar nicht bewusst
 
Danke für die schnelle und vor allem sehr hilfreiche und einleuchtende Antwort.
rücke Labels nach links
Was war mit den "Labels" genau gemeint?

Den Code hab ich jetzt kurzerhand geändert und macht jetzt auch von der Struktur her mehr Sinn (was ich vorher natürlich alles nicht beachtet habe.) War jetzt nur noch zu faul alles ins Englische und auf die lower-case-art zu achten, werds mir aber in Zukunft merken :) Dass ich die ausg()-Funktion für meine printgroup()-Funktion verwenden kann hab ich garnicht bedacht, finde ich aber schlicht und genial ;)

Code:
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::cin;
using std::string;
using std::endl;

class Person
{
   private:
     string Geschlecht;
     string Name;
     float Abschluss;

   public:
     void add(string name, string geschlecht, float note);
     void ausg();
};

class Group
{
   private:
     std::vector<Person> Gruppe;

   public:
     void addgroup(Person pe);
     void printgroup();
};

void Person::add (string name, string geschlecht, float note)
{
  Geschlecht = geschlecht;
  Name = name;
  Abschluss = note;
}

void Group::addgroup(Person pe1)
{
  Gruppe.push_back(pe1);
}

void Group::printgroup()
{
    for (size_t i = 0; i < Gruppe.size(); ++i)
    {
       Gruppe[i].ausg();
    }
}

void Person::ausg()
{
  cout << "Person: " << Geschlecht << " " << Name << " ,Note: " << Abschluss << endl;
}

int main()
{
  Person pers1;
  Person pers2;
  Group gruppe1;

  pers1.add("Max", "Mustermann", 2.0);
  pers1.ausg();
  pers2.add("Hans", "Meier", 2.2);
  pers2.ausg();

  gruppe1.addgroup(pers1);
  gruppe1.addgroup(pers2);
  gruppe1.printgroup();
}

ich denke und hoffe dass es jetzt schon besser aussieht und hab für weitere Hinweise gerne ein Ohr offen. Soweit jedenfalls vielen herzlichen Dank.
 
Sieht schon viel besser aus. Das mit den Labels hast du jetzt eh schon so gemacht. Also private: und public: sind Labels, die rückt man aufgrund der Lesbarkeit meist um eine Stufe nach links.

Gruß
BlackMark
 
Finde es übrigens vorbildlich das du explizit using std::cout etc. benutzt und nicht das was man sonst überall sieht, "using namespace std;", womit du dir den ganzen globalen Namespace verpestet (und z.T. wenn du die Windows API nutzt auch Fehler produzieren kannst!).

Was ich empfehlen würde wären das benutzen von sog. Konstruktoren. Du übergibst also schon beim erstellen der "Person" an wie sie heißt, welches Geschlecht und welche Note sie hat.

Als zweiten Punkt bietet es sich an, wenn du das Objekt nicht verändern willst, es als sogenannte const-reference zu übergeben (const Person&). Damit spart sich das Program die Person komplett zu kopieren und übergibt stattdessen nur einen Pointer.

Hier mal meine Implementation:

Code:
#include <iostream>
#include <string>
#include <vector>

using std::string;

class Person {
public:
    Person(const string& name, const string& geschlecht, float note) {
        m_Name = name;
        m_Geschlecht = geschlecht;
        m_Note = note;
    }

    void print() {
        std::cout << "Name: " << m_Name << ", Geschlecht: " << m_Geschlecht << ", Note: " << m_Note << std::endl;
    }

private:
    string m_Name;
    string m_Geschlecht;
    float m_Note;
};

class Gruppe
{
public:
    void add_person(const Person& pe) {
        m_Personen.push_back(pe);
    }
    void print() {
        for (auto& pe : m_Personen) {
            pe.print();
        }
    }

private:
    std::vector<Person> m_Personen;
};
 
int main()
{
  Person pers1("Max", "Mustermann", 2.0f);
  Person pers2("Hans", "Meier", 2.2f);
  Gruppe gruppe1;
 
  gruppe1.add_person(pers1);
  gruppe1.add_person(pers2);
  gruppe1.print();
}
 
BlackMark schrieb:
Frage zurück, warum i++ und nicht ++i?
Also im Prinzip ist es total egal, theoretisch ist ein i++ langsamer, weil es eine temporäre Variable anlegen muss um den Wert vor der Inkrementierung zu speichern, das wird aber ziemlich sicher vom Compiler wegoptimiert und am Ende sollten genau die gleichen Assembly Instructions raus kommen. Ich habe mir halt angewöhnt ++i zu schreiben, weil das eher meiner Intention entspricht. Ich will ja die Variable i um eines erhöhen, mir ist egal ob der Ausdruck zu i oder zu i+1 evaluiert wird, solange i danach um 1 größer ist. Ich verwende i++ nur dann, wenn ich wirklich will, dass der Ausdruck zu i evaluiert und danach erst um eines erhöht wird.

Gruß
BlackMark
Laut https://youtu.be/vrfYLlR8X8k?t=49m11s soll ++I oft sogar langsamer sein.
 
Zuletzt bearbeitet:
Wow, Kontext beachten!
Meine Aussage bezog sich auf for( int i = 0; i < foo; ++i ) und nicht auf a[++i], diese zwei Verwendungen vom Inkrement Operator sind Unterschiedlich was die erzeugten Opcodes angeht, weil, wie im Video auch gesagt wird, a[i++] in weniger Opcodes ausgeführt werden kann als a[++i], das liegt aber am Array Zugriff. Wenn der Inkrement Operator im for Header verwendet wird, dann verhält sich das ganz anders, weil dort kein Array Zugriff stattfindet.
Bei Array Zugriffen ist sowieso die a[i++] Variante fast immer sinnvoller, aufgrund dessen, dass in C und C++ Arrays bei 0 angefangen indiziert werden. Da macht a[++i] wenig Sinn, außer man setzt i initial auf -1, nur wer sowas macht hat sowieso schon verloren.

Gruß
BlackMark
 
Wirklich relevant wird ++i oder i++ wenn du z.B. Iteratoren benutzt.

it++ bewirkt (wenn der compiler nicht schlau genug ist und es weg optimiert), das der Iterator kopiert wird und auf diese Kopie ++ angewendet wird. Je nachdem wie komplex der Iterator ist kann das durchaus in die Performance gehen!

Bei normalen Integers ist aber eigentlich jeder nicht antike Compiler intelligent genug ++i und i++ entsprechend zu optimieren wenn man es nur in einer Schleife benutzt.
 
Zurück
Oben