C++ Variables Attribut ansprechen

Hallo WWWler,

ich bin ein Neuling im Gebiet C++ (habe vorher mit Visual Basic programmiert), aber habe trotzdem eine Frage. Ich hoffe, dass ich hier richtig bin, weil ich mit Visual C++ 2008 arbeite, aber ich denke, meine Frage bezieht sich auf standart C++ (ansonsten bitte verschieben!).

Sagen wir eine Klasse „DVD“ hat die Attribute .Titel, .Genre, und .Beschreibung vom Typ string, auf die die Methode „suchen“ zugreifen kann. „DVDListe“ ist ein Vektor mit Elementen vom Typ „DVD“.
Die Methode „suchen“ soll die Argumente suchFeld und suchWort haben, damit ich keine 3 Methoden für jedes Attribut schreiben muss, und alle DVDs, die dem Suchbegriff entsprechen, als Vektor zurückliefern.

vector suchen(??? suchFeld, string& suchWort) {
 vector li;
 for(unsigned int i(0); i 

Allerdings weiß ich nicht, wie ich das mit dem Suchfeld hinkriegen soll. Gibt es da eine halbwegs einfache Lösung? Wäre sehr dankbar für Codeschnippsel oder Schlagwörter, nach denen ich suchen kann.

Schonmal vielen Dank,
Gruß, Simon

Hallo WWWler,

Hi auch

vector suchen(??? suchFeld, string& suchWort) {
vector li;
for(unsigned int i(0); i

mein vorschlag

suche ( string Attribut , string Wort)
{
string Inhalt = DVDListe[i].getAttrString(Attribut);
if(Inhalt.find(Wort) != string::npos)

neue funktion :

string DVD::getAttrString(String Attribut)
{
if (Attribut == „Titel“) return Titel;
if (Attribut == „Genre“) return Genre;
if (Attribut == „Beschreibung“) return Beschreibung;
}

nur mal so eine idee
natürlich ungetestet etc.

Hallo RakonDark,

vielen Dank für deine Antwort, war sehr hilfreich. Ich werde es dann wohl so machen!

Gruß, Simon

Hallo Simon,

eins nur: Tu Dir den Gefallen und verwende enums statt eines Strings. Das hat mehrere Vorteile, die da zum Beispiel wären:

  1. Du kannst das auch in einem switch…case verwenden
  2. Der Compiler findet Deine Tippfehler
  3. diverse CodeSense - Funktionen der IDEs helfen Dir bei der Eingabe
  4. der Vergleich auf enums sollte effizienter sein als der auf Strings

Gruß
Martin

Hallo

Sagen wir eine Klasse „DVD“ hat die Attribute .Titel, .Genre,
und .Beschreibung vom Typ string, auf die die Methode „suchen“
zugreifen kann. „DVDListe“ ist ein Vektor mit Elementen vom
Typ „DVD“.
Die Methode „suchen“ soll die Argumente suchFeld und suchWort
haben, damit ich keine 3 Methoden für jedes Attribut schreiben
muss, und alle DVDs, die dem Suchbegriff entsprechen, als
Vektor zurückliefern.

vector suchen(??? suchFeld, string& suchWort) {
vector li;
for(unsigned int i(0); i

Ich würde hier eine mehr C+±idiomatische Lösung wählen.
Als erstes würde ich überlegen, wie ich es gerne hätte,
daß mein Interface zur Klasse aussieht. nehmen wir mal
an, es sollte so aussehen:

 int main(int argc, char\*argv[])
{
 DVDSammlung sammlung;

 sammlung.add( DVD("After The Gold Rush","Rock","Neil Young|1970|After The Gold Rush") );
 sammlung.add( DVD("Live Rust","Rock","Neil Young|1979|Live Rust") );
 sammlung.add( DVD("Harvest","Rock","Neil Young|1972|Harvest") );

 {
 cout 

Sprich: wir haben 3 Klassen, eine ist
die "DVD" selber, die die Daten enthält,
eine zweite ist die "DVDListe" welche
eine Art "Feld" von DVD's ist und die
dritte ist unsere "DVDSammlung", welche
zur DVDListe noch ein Interface für
Suchen (suche\_nach) und Hinzufügen (add)
beisteuert.

Für die Suche selber könnte man, um sich die 
Sache übersichtlicher zu gestalten, das Paar 
"suchfeld" und "suchwort" zu einer Hilfsklasse 
"Anfrage" zusammenzubauen.

Wenn einem dann so ein Entwurf (s.o.) gefällt
und zweckmäßig erscheint, geht man an die 
Implementierung.

So eine "DVDSammlung"-Klasse mit Such- und
Hinzufügefunktion könnte beispielsweise so 
aussehen:



    
    
    class DVDSammlung : public DVDListe {
    public:
     void add(const DVD& dvd) { push\_back(dvd); }
    
     DVDListe suche\_nach(const Anfrage& suchbedingung) {
     DVDListe resultat;
     for(DVDListe::iterator it=begin(); it!=end(); it++) 
     if( suchbedingung(\*it) ) resultat.push\_back(\*it);
     return resultat;
     }
    };
    




Jetzt fehlt nur noch die Implementierung von "DVD"
und "Anfrage". DVDListe ist dann schlicht ein vector


Viel Spaß & Grüße

CMБ

Hallo Martin,

eins nur: Tu Dir den Gefallen und verwende enums statt eines
Strings.

Danke für den Tipp, enums waren mir bisher unbekannt, bzw. sind es noch. Meinst du Enums wie sie hier z. B. beschrieben sind ( http://tutorial.schornboeck.net/enum.htm )?
Dann verstehe ich nicht ganz, wie diese den Typ String ersetzten sollen. Hast du vielleicht ein kleines Beispiel?

Gruß, Simon

Hallo CME,

Vielen Dank für deine ausführliche Antwort!!

Sprich: wir haben 3 Klassen, eine ist
die „DVD“ selber, die die Daten enthält,
eine zweite ist die „DVDListe“ welche
eine Art „Feld“ von DVD’s ist und die
dritte ist unsere „DVDSammlung“, welche
zur DVDListe noch ein Interface für
Suchen (suche_nach) und Hinzufügen (add)
beisteuert.

Einiges hatte ich auch schon so, wie du es vorgeschlagen hast, wie z. B. die Klasse „DVD“ und eine zweite Klasse, in der die DVDs als Vektor gespeichert sind. Genau so die Methode zum Hinzufügen einer DVD und hier sollte auch die Methode zum Suchen untergebracht werden.

Für die Suche selber könnte man, um sich die
Sache übersichtlicher zu gestalten, das Paar
„suchfeld“ und „suchwort“ zu einer Hilfsklasse
„Anfrage“ zusammenzubauen.

Wenn einem dann so ein Entwurf (s.o.) gefällt
und zweckmäßig erscheint, geht man an die
Implementierung.

So eine „DVDSammlung“-Klasse mit Such- und
Hinzufügefunktion könnte beispielsweise so
aussehen:

class DVDSammlung : public DVDListe {
public:
void add(const DVD& dvd) { push_back(dvd); }

DVDListe suche_nach(const Anfrage& suchbedingung) {
DVDListe resultat;
for(DVDListe::iterator it=begin(); it!=end(); it++)
if( suchbedingung(*it) ) resultat.push_back(*it);
return resultat;
}
};

Jetzt fehlt nur noch die Implementierung von „DVD“
und „Anfrage“. DVDListe ist dann schlicht ein
vector

Ich werde jetzt gleich versuchen, die Suche so umzusetzten, wie du es beschrieben (nachdem ich erstmal google, was ein Iterator ist).

Viel Spaß & Grüße
CME

Danke, werde ich haben,
Gruß, Simon

Hallo Simon,

Einiges hatte ich auch schon so, wie du es vorgeschlagen hast,
wie z. B. die Klasse „DVD“ und eine zweite Klasse, in der die
DVDs als Vektor gespeichert sind. Genau so die Methode zum
Hinzufügen einer DVD und hier sollte auch die Methode zum
Suchen untergebracht werden.


Ich werde jetzt gleich versuchen, die Suche so umzusetzten,
wie du es beschrieben (nachdem ich erstmal google, was ein
Iterator ist).

Ein „Iterator“ ist faktisch ein „Zeiger“, mit dem man
über die Elemente eines STL-Containers laufen kann,
z.B. über std::vector. Und da die von mir vorgeschlagene
„DVDListe“ ein vector ist, geht das ohne weiteres.

In der besagten Funktion in der Klasse „DVDSammlung“:

 ...
 DVDListe suche\_nach(const Anfrage& suchbedingung) {
 DVDListe resultat;

1: for(DVDListe::const\_iterator it=begin(); it!=end(); it++) 
2: if( suchbedingung(\*it) ) 
3: resultat.push\_back(\*it);

 return resultat;
 }
 ...

bezieht sich das „begin()“ auf den vector selbst, der
diese eine Elementfunktionen (begin,end) besitzt:

 ...
 class DVDSammlung : public DVDListe {
 ...

sprich: DVDListe ist ja ein vector und hat
das begin() und end() von einem std::vector be-
kommen. DVDSammlung *ist* damit auch ein vector.

Beide Funktionen (begin,end) liefern so einen Iterator,
den auf den Anfang und den *hinter* dem letzten Element.

Die Elemente dieses vector sind jeweils
ein Element der Klasse DVD, da ein Iterator ein
Zeiger ist, muß man ihn dereferenzieren (mit ‚*‘).

Die Hilfsklasse „Anfrage“ (mit der übergebenen
Variablen „suchbedingung“) hat im obigen beispiel
einen

 ...
 bool operator() (const DVD& dvd) { return passt/passt nicht ... }
 ...

sprich: wenn da steht:

 ...
 if( suchbedingung(\*it) ) ...
 ...

wird eigentlich aufgerufen:

 ...
 if( Anfrage::suchbedingung.operator()(\*it) ) ...
 ...

Das ist das sog. Operator-Overloading.

In so einer überladenen Operatorfunktion kann
man dann den eigentlichen Vergleich verstecken:

 ...
 class Anfrage : public pair {
 public:
 Anfrage(DVD::SuchFeld f, const string& s) : pair(f, s) {}
 bool operator() (const DVD& dvd) const { return dvd.ElementVon(first) == second; }
 };
 ...

Hier hatte ich mir überlegt, daß die Klasse DVD einfach
eine zusätzliche Funktion „ElementVon(welchesAttribut)“
bekommt, welche dann anhand eines „enums“ entscheidet,
was abgefragt wird:

 ...
 class DVD { 
 ...
 public: 
 enum SuchFeld { TITEL, GENRE, BESCHREIBUNG };
 ...
 ...

 string ElementVon(SuchFeld suchfeld) const { 
 switch(suchfeld) {
 case TITEL: return m\_titel;
 case GENRE: return m\_genre;
 case BESCHREIBUNG: return m\_beschreibung;
 default: return "Fehler!";
 }
 }
 ...

usw. Der Anfrage::operator()(DVD&amp:wink: würde dann den
Vergleich mit der Rückgabe der DVD::ElementVon()
durchführen.

Viele Grüße

CMБ

1 Like