Suchfunktion in einer Klasse mit mehreren Instanzen



  • @Lumberjack
    Ist C++20 nicht schön?

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <ranges>
    #include <string>
    
    class Car
    {
    private:
        std::string mName;
        unsigned int mTopSpeed;
        unsigned int mHorsepower;
        double mWeight;
    
    public:
        Car() :     // Initialisert die Klasse mit den Standardwerten 
            mName(""),
            mTopSpeed(100),
            mHorsepower(50),
            mWeight(900) {
        }
    
        Car(const std::string& Name, unsigned int TopSpeed, unsigned int Horsepower, double Weight) :
            mName(Name),
            mTopSpeed(TopSpeed),
            mHorsepower(Horsepower),
            mWeight(Weight)
        {}
    
        std::string GetName() const {
            return mName;
        }
    
        unsigned int GetTopSpeed() const {
            return mTopSpeed;
        }
    
        unsigned int GetHorsepower() const {
            return mHorsepower;
        }
    
        double GetWeight() const {
            return mWeight;
        }
    };
    
    int main()
    {
        std::vector<Car> L{
            Car("Audi A3", 200, 100, 1500),
            Car("Daccia", 299, 350, 1900),
            Car("BMW", 325, 500, 1800),
            Car("Opel", 312, 390, 1555),
        };
        double MinWeight = 1525;
        double MaxWeight = 1850;
    
        for (const Car& c : L | std::views::filter([&](const Car& ci) {
            return ci.GetWeight() > MinWeight && ci.GetWeight() < MaxWeight;
            }))
        {
            std::cout << "Car: Name = \"" << c.GetName() <<
                "\"\tTopSpeed = " << c.GetTopSpeed() <<
                "\tHorsepower = " << c.GetHorsepower() <<
                "\tWeight = " << c.GetWeight() << "\n";
        }
            return 0;
    }
    

    Versionshistorie:

    • 1.01: Umstellung der konstanten Attribute auf private, nicht konstante Attribute, da diese besser mit std::vector bzw. std::vector<>::resize() arbeitet.


  • @Quiche-Lorraine
    Nice!

    Edit:
    Aber müssen die Attribute alle const sein? Macht das Handling etwas schwierig, weil man keine Kopien machen kann. Von daher würde ich entweder das const entfernen oder die Attribute privat machen und nur lesende Funktionen ergänzen.



  • Jetzt mal ernsthaft ... Wieso wurde mein Codevorschlag mehrfach(!) negativ bewertet? Sind die Deppen wieder los?

    @Quiche-Lorraine Sieht ganz gut aus.



  • @DocShoe sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Aber müssen die Attribute alle const sein?

    Nö, mit private Variablen wäre ich auch zufrieden.

    Aber die Attribute haben etwas konstantes an sich, da sich diese nicht ändern werden.

    Macht das Handling etwas schwierig, weil man keine Kopien machen kann.

    Diesen Satz verstehe ich nicht da...

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <ranges>
    #include <string>
    
    class Car
    {
    public:
        const std::string mName;
        const unsigned int mTopSpeed;
        const unsigned int mHorsepower;
        const double mWeight;
    private:
        double mFuelCapacity = 0;           // 0 = Tank leer, 1 = Tank voll 
    
    public:
        Car(const std::string& Name, unsigned int TopSpeed, unsigned int Horsepower, double Weight) :
            mName(Name),
            mTopSpeed(TopSpeed),
            mHorsepower(Horsepower),
            mWeight(Weight)
        {}
    
        void SetFuel(double Capacity)
        {
            if ((Capacity < 0) && (Capacity > 1))
                throw std::out_of_range("Fuel must be beetween 0 and 1");
            mFuelCapacity = Capacity;
        }
    
        double GetFuel() const
        {
            return mFuelCapacity;
        }
    };
    
    
    int main()  // Testcode
    {
        std::vector<Car> L;       
        Car a1("Opel", 312, 390, 1555);
        //Car a3;     // Fehler, da kein Standardkonstruktor vorhanden ist. Ist ok.
    
        for (int i = 0; i < 100; i++)
        {
            Car a2 = a1;
    
            a2.SetFuel(i / 100.0);
            L.push_back(a2);
        }
        std::for_each(std::begin(L), std::end(L), [](const Car& c) {
            std::cout << "Car: Name = \"" << c.mName <<
                "\"\tTopSpeed = " << c.mTopSpeed <<
                "\tHorsepower = " << c.mHorsepower <<
                "\tWeight = " << c.mWeight <<
                "\tFuel = " << c.GetFuel() << "\n";
            });
        return 0;
    }
    

    Selbst std::vector scheint mit Klassen ohne Standardkonstruktor zurechtzukommen. Warum das so ist, weis ich aber nicht.



  • @Quiche-Lorraine

    Vermutlich, weil std::vector in deinem Fall mit move auskommt und Objekte verschiebt, statt sie zu kopieren.
    L.resize( 105 ) geht aber nicht, da in diesem Fall tatsächlich Car-Objekte default-konstruiert und kopiert werden müssen.



  • Ich würde auch auf const verzichten in dem Fall, und stattdessen (nur) mit Gettern arbeiten.

    Ich hab noch keine Begründung gesehen, was an meinem Code soo falsch sein soll.



  • @Fragender

    An deinem Code ist so ziemlich alles falsch oder schlecht designed, was man so machen kann. Hat Jürgen-Wolf-Qualität. Gibt aber einen Pluspunkt, weil wenigstens nix von Wurstbroterbt. Oder von Supermarkt? Weiß nicht mehr so genau.

    1. Der Name der Klasse Element ist irreführend. Ja, es ist ein Listenelement, aber primär ist es eine Klasse für Fahrzeugdaten.

    2. Warum intrusiv? Ein Auto muss seinen Nachfolger nicht kennen. Mir fällt auch spontan kein Fall ein, wo man eine intrusive Liste bräuchte.

    3. Unklare Besitzverhältnisse der rohen Zeiger. Wer ist für die Freigabe verantwortlich? Und generell ist der Zwang, Elemente auf dem Heap zu erzeugen, unnötig und kann besser gelöst werden. Dein Code löst das gar nicht, weil er den Speicher erst gar nicht mehr freigibt.

    4. Single Responsibility Principle wird verletzt: Deine Liste speichert nicht nur Elemente, sondern filtert und gibt sie auch aus. Gehört da nicht rein und sollte extern gelöst werden. Geht natürlich nicht, weil deine Liste keinen Zugriff auf die einzelnen Elemente zulässt.

    5. Die "interessante" filterPrint-Funktion ist kompletter Humbug. Statt direkt auf Attribute zuzugreifen wird zur Laufzeit ein Attributname vergeben, anhand dessen in zwei std::maps nach entsprechenden Memberfunktionen gesucht wird, die zur Bestimmung des Vergleichswertes zum Filtern benutzt werden. Langsam, fehleranfällig und unflexibel. Man kann nur nach einem Kriterium filtern, und dann muss auch noch ein Bereich festgelegt werden. Wird spätestens dann lustig, wenn man alle Mercedes haben möchte....

    6. Wiederverwendbarkeit: Nada. Dein Code löst genau nur das eine Problem. Wenn man schon einen eigenen hust "Container" baut, dann sollte der wiederverwendbar sein, zumindest, wenn man sich für einen fortgeschrittenen Programmierer hält.

    Eine Idee für eine wiederverwendbare doppelt verkettete Liste könnte so ausehen. Hier nur der Ansatz, die Fleißaufgabe überlasse ich dir. Insbesondere das Kopieren und Aufräumen.

    template<typename T>
    class linked_list
    {
    public:
       using value_type = T;
       using const_reference = T const&;
    
    private:
       struct list_node
       {
          list_node* Pred = nullptr;
          list_node* Succ = nullptr;
          value_type Value;
    
          list_node( const_reference value ) :
             Value( value )
          {
          }
       };
       
       list_node* Head_ = nullptr;
       list_node* Tail_ = nullptr;
    
    public:
       linked_list() = default;
       ~linked_list()
       {
          // to do  
       }
    
       // Kopien/Zuweisungen verbieten
       linked_list( linked_listconst& other ) = delete;
       linked_list& operator=( linked_list const& other ) = delete;
    
       // Move erlauben
       linked_list( linked_list&& other ) :
          Head_( std::move( other.Head_ ),
          Tail_( std::move( other.Tail_ )
       {
       }
    
       linked_list& operator=( linked_list&& other )
       {
          Head_ = std::move( other.Head_ );
          Tail_ = std::move( other.Tail_ );
          return *this;
       }
    
       void append( const_reference value )
       {
          // to do
       }
    };
    

    Da haste noch genug Platz zum Austoben...

    Oder man spart sich den ganzen Quatsch und benutzt std::vector, der, wie @Quiche-Lorraine sehr schön gezeigt hat, die STL Algos unterstützt und man kaum selbst was programmieren muss. Das C++20 Filter-Feature kannte ich noch nicht, aber boost hat sowas auch.



  • @DocShoe sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Vermutlich, weil std::vector in deinem Fall mit move auskommt und Objekte verschiebt, statt sie zu kopieren.
    L.resize( 105 ) geht aber nicht, da in diesem Fall tatsächlich Car-Objekte default-konstruiert und kopiert werden müssen.

    Du hast mich überzeugt.

    So ein nicht funktionierendes resize() ist aus meiner Sicht ein unerwünschter Seiteneffekt. Und eine Definition eines Standardkonstruktors Car ist ja auch problemlos möglich.



  • @Quiche-Lorraine sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    @DocShoe sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Vermutlich, weil std::vector in deinem Fall mit move auskommt und Objekte verschiebt, statt sie zu kopieren.
    L.resize( 105 ) geht aber nicht, da in diesem Fall tatsächlich Car-Objekte default-konstruiert und kopiert werden müssen.

    Du hast mich überzeugt.

    So ein nicht funktionierendes resize() ist aus meiner Sicht ein unerwünschter Seiteneffekt. Und eine Definition eines Standardkonstruktors Car ist ja auch problemlos möglich.

    Ist ja nicht so, dass ich in meinem Code sowas nicht auch schon mal probiert hätte 😉 In meinem Fall hatten Objekte eine eindeutige ID, die ich nicht mehr ändern lassen wollte.



  • Zu 6.: Das hat @Quiche-Lorraine doch auch nicht anders gemacht.

    Keiner der Kritikpunkte, bis auf 3., ist gerechtfertigt.

    Das war's dann hier für mich, viel Spaß noch bei dem Unsinn.



  • @Ein-ehemaliger-Benutzer sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Zu 6.: Das hat @Quiche-Lorraine doch auch nicht anders gemacht.

    Keiner der Kritikpunkte, bis auf 3., ist gerechtfertigt.

    Das war's dann hier für mich, viel Spaß noch bei dem Unsinn.

    Allein das war's wert.



  • @Ein-ehemaliger-Benutzer sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Zu 6.: Das hat @Quiche-Lorraine doch auch nicht anders gemacht.

    Keiner der Kritikpunkte, bis auf 3., ist gerechtfertigt.

    Das war's dann hier für mich, viel Spaß noch bei dem Unsinn.

    Ich werde Dich sehr vermissen ...



  • Ich finds ja schade. Hat immer viel Code gezeigt, und auch wenn mal schlechter Code darunter gewesen ist, auch davon kann man lernen, solange andere ihn korrigieren.



  • @zeropage

    Ich finds ja schade. Hat immer viel Code gezeigt, und auch wenn mal schlechter Code darunter gewesen ist, auch davon kann man lernen, solange andere ihn korrigieren.

    Das finde ich bezogen auf Fragender ein wenig widersprüchlich, da Selbstreflektion war noch nie seine Stärke war. Und eine pampige Antwort der Form

    Keiner der Kritikpunkte, bis auf 3., ist gerechtfertigt. Das war's dann hier für mich, viel Spaß noch bei dem Unsinn."

    habe ich ehrlich gesagt schon erwartet.

    Wenn ich meinen Code nicht präsentiert hätte, dann hätte @Lumberjack einen völlig veralteten und fehlerhaften Eindruck von modernem C++ bekommen. Vielleicht mag man von schlechten Code etwas lernen können, dieser ist aber mindestens im gleichen Maße gefährlich, da alte totgesagte Fehler so immer wieder ans Licht kommen und die Anfänger verwirren.



  • @Quiche-Lorraine sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    Wenn ich meinen Code nicht präsentiert hätte, dann hätte @Lumberjack einen völlig veralteten und fehlerhaften Eindruck von modernem C++ bekommen.

    Aber Du hast ihn ja korrigiert. Also ist doch gut. Ich meine auch, zum Lernen gehört auch die Unterschiede in der Codequalität zu erkennen. Als blutiger Anfänger hat man erst mal einen riesigen Pool an Informationen, die man nicht einordnen kann, aber mit der Zeit, wenn man am Ball bleibt, fängt man doch an, die Spreu vom Weizen zu trennen.

    So funktioniert das ja auch bei anderen Themen. Je mehr man sich damit beschäftigt, desto besser kann man differenzieren. Jedenfalls kenn ich das so.

    Und ich denke, bei jedem Thema sind die tatsächlichen Könner eine Minderheit, weshalb schlechte Angewohnheiten nun mal öfters auftreten. Aber davon kann man eben auch lernen.



  • @zeropage

    Bei Fragendem hat das ja immer noch ein Nachspiel. Erst versucht er, seinen Ansatz iwie zu rechtfertigen bzw. die Kritik als unberechtigt darzustellen, und wenn das nicht klappt lenkt er vom Thema ab. Dann muss man ein zweites/drittes Mal zeigen, dass er daneben liegt und gleichzeitig den Thread wieder in die richtige Richtung lenken.
    Insgesamt ein schwieriger Charakter.

    Edit:
    Ich will mich jetzt nicht durch all seine Beiträge wühlen, aber was davon war jetzt wirklich gut und brauchbar? Gefühlt 75% seiner Beiträge waren irgendwelche sehr speziellen Fragen, die er alle 2h durch eigene Erkenntnisse ergänzt hat. Das waren meistens Monologe, und wenn jemand nachgefragt oder was anderes vorgeschlagen hat wurde er sofort pampig.
    Insgesamt ein sehr schwieriger Charakter.



  • in 2 wochen ist er mit neuem account wieder hier und macht da weiter wo er aufgehoert hat...



  • Ist ja etwas wild geworden hier 😅
    Bin noch etwas am Üben und tun. Werde demnächst den Code hier posten.


  • Gesperrt

    @Cardiac sagte in Suchfunktion in einer Klasse mit mehreren Instanzen:

    in 2 wochen ist er mit neuem account wieder hier und macht da weiter wo er aufgehoert hat...

    Du kannst dich schon eher freuen ...

    Das Problem ist doch, dass ich schlechte Reviews und schlechte Menschen erkennen kann. Wenn dann auch noch keine Gegenargumentation erlaubt ist, dann hat so ein Forum seinen Zweck verfehlt.

    Die zweite Sache ist die mit den negativen Bewertungen, die mich stört, und die ich auch schon einmal woanders erwähnt hatte. Es sollte mind. eine Schwelle geben, ab der man andere erst schlecht bewerten darf; denn ansonsten wird so eine Funktion bei jeder Meinung, die einem nicht gefällt, ausgenutzt.



  • Das ist jetzt interessant. Ist die eigene Löschung doch eine Affekthandlung, wie ich es schon bei jemand früheren vermutet habe?

    Denn eigentlich will man doch noch weiter teilnehmen?


Anmelden zum Antworten