Klasse X sortieren?



  • Wie muss die Klasse X modifiziert werden, damit sort funktioniert?

    #include <vector>       
    #include <algorithm>    
    #include <iostream>
    #include <conio.h>
    
    using namespace std;
    
    class Xint
    {
    private:
      int num;  
    
    public:
      Xint(){std::cout<<this<<": "<<"ctor"<<std::endl;}
    
     ~Xint(){std::cout<<this<<": "<<"dtor"<<std::endl;}
    
      Xint(const Xint& x)
      {
          std::cout << this << ": " << "copycon von " << &x << std::endl;
          num = x.getNum();
      }
    
      Xint& operator=(const Xint& x)
      {
          if(&x == this)
          {
              std::cout << "Selbstzuweisung mit op= verhindert!" << endl;       
              return *this;
          }    
          std::cout << this << ": " << "op= von " << &x << std::endl; 
          num = x.getNum();
          return *this;
      }
      int getNum() const {return num;}
      void setNum(int val) {num = val;}
    };
    
    ostream& operator<< (ostream& os, Xint& x)
    {
      cout << x.getNum();
      return os;
    }
    
    bool operator< (Xint& a, Xint& b)
    {
        if(a.getNum() < b.getNum()) return true;
    }
    
    bool operator> (Xint& a, Xint& b)
    {
        if(a.getNum() > b.getNum()) return true;
    }
    
    bool operator== (Xint& a, Xint& b)
    {
        if(a.getNum() == b.getNum()) return true;
    }
    
    int main () 
    {
        vector<Xint> v;
        int n;
        do
        {
           cin >> n;
           if ( n == 0 ) break;
           Xint x; 
           x.setNum(n);
           v.push_back(x);       
        } 
        while (true);
    
        //sort( v.begin(),v.end() );
    
        for ( unsigned int i=0; i<v.size(); ++i )
            cout << v[i] << endl;
        getch();
    }
    


  • Statt:

    bool operator< (Xint& a, Xint& b)
    {
        if(a.getNum() < b.getNum()) return true;
    }
    

    Das:

    bool operator< (Xint& a, Xint& b)
    {
        return a.getNum() < b.getNum();
    }
    


  • Die Parameter des op< müssen const sein.



  • danke, geht:

    bool operator< (const Xint& a, const Xint& b)
    {
        return a.getNum() < b.getNum(); 
    }
    
    bool operator> (const Xint& a, const Xint& b)
    {
        return a.getNum() > b.getNum(); 
    }
    
    bool operator== (const Xint& a, const Xint& b)
    {
        return a.getNum() == b.getNum(); 
    }
    


  • Beispiel:

    #include <vector>       
    #include <algorithm>    
    #include <iostream>
    #include <conio.h>
    
    using namespace std;
    
    class Xint
    {
    private:
      int num;  
    
    public:
      Xint(){std::cout<<this<<": "<<"ctor"<<std::endl;}
    
     ~Xint(){std::cout<<this<<": "<<"dtor"<<std::endl;}
    
      Xint(const Xint& x)
      {
          std::cout << this << ": " << "copycon von " << &x << std::endl;
          num = x.getNum();
      }
    
      Xint& operator=(const Xint& x)
      {
          if(&x == this)
          {
              std::cout << "Selbstzuweisung mit op= verhindert!" << endl;       
              return *this;
          }    
          std::cout << this << ": " << "op= von " << &x << std::endl; 
          num = x.getNum();
          return *this;
      }
      int getNum() const {return num;}
      void setNum(int val) {num = val;}
    };
    
    ostream& operator<< (ostream& os, Xint& x)
    {
      cout << x.getNum();
      return os;
    }
    
    bool operator< (const Xint& a, const Xint& b)
    {
        return a.getNum() < b.getNum(); 
    }
    
    bool operator> (const Xint& a, const Xint& b)
    {
        return a.getNum() > b.getNum(); 
    }
    
    bool operator== (const Xint& a, const Xint& b)
    {
        return a.getNum() == b.getNum(); 
    }
    
    int main () 
    {
        vector<Xint> v;
        int n;
        do
        {
           cin >> n;
           if ( n == 0 ) break;
           Xint x; 
           x.setNum(n);
           v.push_back(x);       
        } 
        while (true);
    
        sort( v.begin(),v.end() );
    
        for ( unsigned int i=0; i<v.size(); ++i )
            cout << v[i] << endl;
        getch();
    }
    
    3
    0x22ff38: ctor
    0x3f2690: copycon von 0x22ff38
    0x22ff38: dtor
    2
    0x22ff38: ctor
    0x3f2698: copycon von 0x3f2690
    0x3f269c: copycon von 0x22ff38
    0x3f2690: dtor
    0x22ff38: dtor
    1
    0x22ff38: ctor
    0x3f2560: copycon von 0x3f2698
    0x3f2564: copycon von 0x3f269c
    0x3f2568: copycon von 0x22ff38
    0x3f2698: dtor
    0x3f269c: dtor
    0x22ff38: dtor
    0
    0x22fe00: copycon von 0x3f2564
    0x3f2564: op= von 0x3f2560
    0x3f2560: op= von 0x22fe00
    0x22fe00: dtor
    0x22fe00: copycon von 0x3f2568
    0x3f2568: op= von 0x3f2564
    0x3f2564: op= von 0x3f2560
    0x3f2560: op= von 0x22fe00
    0x22fe00: dtor
    1
    2
    3
    

    Damit kann man die Klasse Xint als "Sonde" (zu Lehrzwecken) für Container und Algorithmen z.B. aus der STL verwenden. Habt ihr Ideen, wie man diese Klasse verbessern könnte, um noch mehr Infos zu erhalten?



  • Der operator< reicht für sort übrigens. Nur so am Rande bemerkt.



  • Stimmt! Ich wollte die Klasse Xint möglichst universell aufbauen zum Vorführen der Vor- und Nachteile verschiedener Strategien im Rahmen der STL. Man kann z.B. sofort zeigen, dass es Sinn macht, v.reserve(...) anzuwenden oder was es bedeutet einen insert in den Anfangsbereich eines vectors im Vergleich zu list zu machen, etc. Obiges Programm zeigt, wie push_back oder sort arbeitet.

    Man tausche oben z.B. vector gegen deque aus. Man sieht sofort den Vorteil bezüglich push_back:

    3
    0x22ff18: ctor
    0x3f2500: copycon von 0x22ff18
    0x22ff18: dtor
    2
    0x22ff18: ctor
    0x3f2504: copycon von 0x22ff18
    0x22ff18: dtor
    1
    0x22ff18: ctor
    0x3f2508: copycon von 0x22ff18
    0x22ff18: dtor
    0
    0x22fd60: copycon von 0x3f2504
    0x3f2504: op= von 0x3f2500
    0x3f2500: op= von 0x22fd60
    0x22fd60: dtor
    0x22fd60: copycon von 0x3f2508
    0x3f2508: op= von 0x3f2504
    0x3f2504: op= von 0x3f2500
    0x3f2500: op= von 0x22fd60
    0x22fd60: dtor
    1
    2
    3
    


  • Erhard Henkes schrieb:

    if(&x == this)
          {
              std::cout << "Selbstzuweisung mit op= verhindert!" << endl;       
              return *this;
          }
    

    Das würde ich nicht machen, da Selbstzuweisung ein "natürliches Phänomen" ist. Wenn die Klasse als "Sonde" dienen soll, würde ich die built-in Funktionalität von int nicht brechen. Also ein einfaches

    if (&x == this)
    {
        std::cout << "Selbstzuweisung mit op=" << std::endl;
    }
    

    reicht imo.

    btw:
    Beim Editieren deines Codes ist mir aufgefallen, dass std:: mal benutzt wird und mal nicht. 😕



  • Ja, das ist richtig, hier muss man nicht unbedingt abfangen.

    Beim Editieren deines Codes ist mir aufgefallen, dass std:: mal benutzt wird und mal nicht.

    Klasse als Header sollte kein namespace std freigeben (ist oben nur aus header und cpp kombiniert).



  • z.B. Vergleich list und vector:

    int main () 
    {
        const int N = 3;
        Xint x;
        list<Xint> l;
        list<Xint>::iterator it;
    
        for(int i=0; i<N; ++i)
        {
            x.setNum(i); 
            l.push_back(x);
        }
        cout << endl;
    
        x.setNum(42);
        it = l.begin();
        l.insert(++it,x);
        cout << endl;
    
        for(it=l.begin();it!=l.end();++it)
        {
            cout << *it << endl;
        }    
        getch();
    }
    
    0x22ff58: ctor
    0x3f2540: copycon von 0x22ff58
    0x3f2550: copycon von 0x22ff58
    0x3f2560: copycon von 0x22ff58
    
    0x3f2570: copycon von 0x22ff58
    
    0
    42
    1
    2
    
    //...
        vector<Xint> l;
        vector<Xint>::iterator it;
    //...
    
    0x22ff58: ctor
    0x3f2528: copycon von 0x22ff58
    0x3f2530: copycon von 0x3f2528
    0x3f2534: copycon von 0x22ff58
    0x3f2528: dtor
    0x3f25c8: copycon von 0x3f2530
    0x3f25cc: copycon von 0x3f2534
    0x3f25d0: copycon von 0x22ff58
    0x3f2530: dtor
    0x3f2534: dtor
    
    0x3f25d4: copycon von 0x3f25d0
    0x22fe40: copycon von 0x22ff58
    0x3f25d0: op= von 0x3f25cc
    0x3f25cc: op= von 0x22fe40
    0x22fe40: dtor
    
    0
    42
    1
    2
    

    Da ich eine solche Visualisierung nirgends gefunden habe, bastele ich mir diese "Sonde". Gibt es irgendwo etwas Ähnliches/Besseres?



  • Was praktisch wäre: bau noch static Zähler ein, die direkt die Anzahl der CopyCtor, Ctor, Dtor, op=, etc. aufrufe mitzählen.

    So dass du dann nur noch
    Xint::statistik(cout);
    machen musst, um eine schöne statistik zu erhalten - und dafür die internen ausgaben per #define an und abschaltbar machen.

    Der Vorteil: du kannst die Klasse dann auch in ein richtiges Programm einbauen und müllst dir die Ausgabe nicht zu. Und die Statistik kann man dann schön zB in Dateien schreiben um sie zu speichern...

    PS:
    im op<< kann Xint const sein 😉



  • Danke! Gute Idee, schon realisiert:
    [EDIT] Funktion reset (s.u.) ebenfalls bereits eingebaut [\EDIT]

    #include <deque>       
    #include <vector>
    #include <list>
    #include <algorithm>    
    #include <iostream>
    #include <conio.h>
    
    using namespace std;
    
    //#define _TEST_
    
    class Xint
    {
    private:
      int num;  
      static int countCtor;
      static int countDtor;  
      static int countCopycon;  
      static int countOpAssign;  
    public:
      Xint()
      {
          #ifdef _TEST_  
          std::cout<<this<<": "<<"ctor"<<std::endl;  
          #endif
          ++countCtor;
      }
    
     ~Xint()
      {
          #ifdef _TEST_  
          std::cout<<this<<": "<<"dtor"<<std::endl;
          #endif      
          ++countDtor;
      }
    
      Xint(const Xint& x)
      {
          #ifdef _TEST_  
          std::cout << this << ": " << "copycon von " << &x << std::endl;
          #endif  
          num = x.getNum();
          ++countCopycon;
      }
    
      Xint& operator=(const Xint& x)
      {
          if (&x == this)
          {
              #ifdef _TEST_            
              std::cout << "Selbstzuweisung mit op=" << std::endl;
              #endif
          }
          #ifdef _TEST_
          std::cout << this << ": " << "op= von " << &x << std::endl; 
          #endif
          num = x.getNum();
          ++countOpAssign;
          return *this;
      }
      int getNum() const {return num;}
      void setNum(int val) {num = val;}
      static void statistik(ostream&);
      static void reset();
    };
    
    int Xint::countCtor     = 0;
    int Xint::countDtor     = 0;  
    int Xint::countCopycon  = 0;  
    int Xint::countOpAssign = 0;  
    
    void Xint::statistik(ostream& os)
    {
      os   << "Ctor:    " << countCtor    << endl 
           << "Dtor:    " << countDtor    << endl
           << "Copycon: " << countCopycon << endl
           << "op=:     " << countOpAssign;   
    }    
    
    void Xint::reset()
    {
        countCtor     = 0;
        countDtor     = 0;  
        countCopycon  = 0;  
        countOpAssign = 0;  
    } 
    
    ostream& operator<< (ostream& os, const Xint& x)
    {
      os << x.getNum();
      return os;
    }
    
    bool operator< (const Xint& a, const Xint& b)
    {
        return a.getNum() < b.getNum(); 
    }
    
    bool operator> (const Xint& a, const Xint& b)
    {
        return a.getNum() > b.getNum(); 
    }
    
    bool operator== (const Xint& a, const Xint& b)
    {
        return a.getNum() == b.getNum(); 
    }
    
    int main () 
    {
    
        const int N = 3;
        Xint x;
        list<Xint> l;
        list<Xint>::iterator it;
    
        for(int i=0; i<N; ++i)
        {
            x.setNum(i); 
            l.push_back(x);
        }
        cout << endl;
    
        x.setNum(42);
        it = l.begin();
        l.insert(++it,x);
        cout << endl;
    
        for(it=l.begin();it!=l.end();++it)
        {
            cout << *it << endl;
        } 
        cout << endl;
    
        Xint::statistik(cout);   
        getch();
    }
    
    0
    42
    1
    2
    
    Ctor:    1
    Dtor:    0
    Copycon: 4
    op=:     0
    


  • ein reset() (setzt alle statistik vars auf 0) wäre dann auch noch praktisch - wenn man nur einen kleinen teil des codes testen will, oder zB list und deque im selben programm



  • Hübsche Idee, bereits implementiert (s.o.). 🙂

    Beispiel: list vs. deque

    int main () 
    {
        const int N = 10;
        Xint x;
    
        list<Xint> l;
        list<Xint>::iterator it;
    
        for(int i=0; i<N; ++i)
        {
            x.setNum(i); 
            l.push_back(x);
        }
        cout << endl;
    
        x.setNum(42);
        it = l.begin();
        l.insert(++it,x);
        cout << endl;
    
        l.erase(--it);
        cout << endl;
    
        for(it=l.begin();it!=l.end();++it)
        {
            cout << *it << endl;
        } 
        cout << endl;
    
        Xint::statistik(cout);   
        Xint::reset();
        cout << endl << endl;    
    
        deque<Xint> d;
        deque<Xint>::iterator iter;
    
        for(int i=0; i<N; ++i)
        {
            x.setNum(i); 
            d.push_back(x);
        }
        cout << endl;
    
        x.setNum(42);
        iter = d.begin();
        d.insert(++iter,x);
        cout << endl;
    
        d.erase(--iter);
        cout << endl;
    
        for(iter=d.begin();iter!=d.end();++iter)
        {
            cout << *iter << endl;
        } 
        cout << endl;
    
        Xint::statistik(cout);   
        getch();
    }
    

    Kurzform:

    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Ctor:    1
    Dtor:    1
    Copycon: 11
    op=:     0
    
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Ctor:    0
    Dtor:    3
    Copycon: 13
    op=:     2
    

    Vorteil für list!

    Langform:

    0x22ff58: ctor
    0x3f2540: copycon von 0x22ff58
    0x3f2550: copycon von 0x22ff58
    0x3f2560: copycon von 0x22ff58
    0x3f2570: copycon von 0x22ff58
    0x3f2580: copycon von 0x22ff58
    0x3f2590: copycon von 0x22ff58
    0x3f25a0: copycon von 0x22ff58
    0x3f25b0: copycon von 0x22ff58
    0x3f25c0: copycon von 0x22ff58
    0x3f25d0: copycon von 0x22ff58
    
    0x3f25e0: copycon von 0x22ff58
    
    0x3f25e0: dtor
    
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Ctor:    1
    Dtor:    1
    Copycon: 11
    op=:     0
    
    0x3f3968: copycon von 0x22ff58
    0x3f396c: copycon von 0x22ff58
    0x3f3970: copycon von 0x22ff58
    0x3f3974: copycon von 0x22ff58
    0x3f3978: copycon von 0x22ff58
    0x3f397c: copycon von 0x22ff58
    0x3f3980: copycon von 0x22ff58
    0x3f3984: copycon von 0x22ff58
    0x3f3988: copycon von 0x22ff58
    0x3f398c: copycon von 0x22ff58
    
    0x22fd80: copycon von 0x22ff58
    0x22fb60: copycon von 0x3f3968
    0x3f3d6c: copycon von 0x22fb60
    0x22fb60: dtor
    0x3f3968: op= von 0x22fd80
    0x22fd80: dtor
    
    0x3f3968: op= von 0x3f3d6c
    0x3f3d6c: dtor
    
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Ctor:    0
    Dtor:    3
    Copycon: 13
    op=:     2
    

    Hat noch jemand interessante Ideen für diese Klasse, die in STL-Containern z.B. als Ersatz dienen soll für ein einfaches int.



  • Habe nun auch noch Farbe bei der Ausgabe auf Konsole implementiert:

    #define _TEST_
    #include <windows.h>
    #include <conio.h>
    #include <iostream>
    
    /*
     0    BLACK,
     1    BLUE,
     2    GREEN,
     3    CYAN,
     4    RED,
     5    MAGENTA,
     6    BROWN,
     7    LIGHTGRAY,
     8    DARKGRAY,
     9    LIGHTBLUE,
    10    LIGHTGREEN,
    11    LIGHTCYAN,
    12    LIGHTRED,
    13    LIGHTMAGENTA,
    14    YELLOW,
    15    WHITE
    */
    
    void textcolor(WORD color) 
    { 
        SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), color); 
    } 
    
    const int farbe1 =  3;
    const int farbe2 = 15;
    
    class Xint
    {
    private:
      int num;  
      static int countCtor;
      static int countDtor;  
      static int countCopycon;  
      static int countOpAssign;  
    public:
      Xint()
      {
          #ifdef _TEST_  
          textcolor(farbe1); 
          std::cout << this << ": " << "ctor" << std::endl;  
          textcolor(farbe2); 
          #endif
          ++countCtor;
      }
    
     ~Xint()
      {
          #ifdef _TEST_ 
          textcolor(farbe1);  
          std::cout << this << ": " << "dtor" << std::endl;
          textcolor(farbe2);
          #endif      
          ++countDtor;
      }
    
      Xint(const Xint& x)
      {
          #ifdef _TEST_
          textcolor(farbe1);  
          std::cout << this << ": " << "copycon von " << std::dec << &x << std::endl;
          textcolor(farbe2);
          #endif  
          num = x.getNum();
          ++countCopycon;
      }
    
      Xint& operator=(const Xint& x)
      {
          if (&x == this)
          {
              #ifdef _TEST_
              textcolor(farbe1);            
              std::cout << "Selbstzuweisung mit op=" << std::endl;
              textcolor(farbe2);
              #endif
          }
          #ifdef _TEST_
          textcolor(farbe1);
          std::cout << this << ": " << "op= von " << std::dec << &x << std::endl; 
          textcolor(farbe2);
          #endif
          num = x.getNum();
          ++countOpAssign;
          return *this;
      }
      int getNum() const {return num;}
      void setNum(int val) {num = val;}
      static void statistik(std::ostream&);
      static void reset();
    };
    
    int Xint::countCtor     = 0;
    int Xint::countDtor     = 0;  
    int Xint::countCopycon  = 0;  
    int Xint::countOpAssign = 0;  
    
    void Xint::statistik(std::ostream& os)
    {
      textcolor(farbe1);  
      os   << "Ctor:    " << countCtor    << std::endl 
           << "Dtor:    " << countDtor    << std::endl
           << "Copycon: " << countCopycon << std::endl
           << "op=:     " << countOpAssign;   
      textcolor(farbe2);     
    }    
    
    void Xint::reset()
    {
        countCtor     = 0;
        countDtor     = 0;  
        countCopycon  = 0;  
        countOpAssign = 0;  
    } 
    
    std::ostream& operator<< (std::ostream& os, const Xint& x) 
    {
      os << x.getNum();
      return os;
    }
    
    bool operator< (const Xint& a, const Xint& b) 
    {
        return a.getNum() < b.getNum(); 
    }
    
    bool operator> (const Xint& a, const Xint& b) 
    {
        return a.getNum() > b.getNum(); 
    }
    
    bool operator== (const Xint& a, const Xint& b) 
    {
        return a.getNum() == b.getNum(); 
    }
    
    bool operator!= (const Xint& a, const Xint& b) 
    {
        return a.getNum() != b.getNum(); 
    }
    


  • Erhard Henkes schrieb:

    Habe nun auch noch Farbe bei der Ausgabe auf Konsole implementiert:

    Hm, und damit ist es jetzt nicht mehr portabel, nimm doch die Improved Console wenn Du unbedingt bunte Ausgabe willst!

    btw: Was hältst Du davon Deine #ifdefs nicht auf TEST testen zu lassen sondern auf NDEBUG oä?



  • Erhard Henkes schrieb:

    Habe nun auch noch Farbe bei der Ausgabe auf Konsole implementiert

    Na wenn das mal nix is. 😃



  • Hm, und damit ist es jetzt nicht mehr portabel, nimm doch die Improved Console wenn Du unbedingt bunte Ausgabe willst!

    Uups, stimmt. Die Linuxer sind draußen. Improved Konsole, gute Idee, habe ich mir noch nie angeschaut. Geht das auf allen Plattformen? Thx.


Anmelden zum Antworten