3. Sztring osztály

Czirkos Zoltán · 2019.02.27.

Sztring osztály, dinamikus tömbre mutató adattag

#include <iostream>
#include <cstring>

class Sztring {
    private:
        size_t hossz;   // lezáró nulla nélkül
        char* adat;     // lezáró nullával együtt

    public:
        Sztring(char const *szoveg = "") {
            hossz = strlen(szoveg);
            adat = new char[hossz+1];
            strcpy(adat, szoveg);
        }

        // Kell destruktor, mert a sztringhez
        // dinamikusan foglalt memóriaterület tartozik.
        ~Sztring() {
            delete[] adat;
        }

        // Ha minden sztringnek saját dinamikusan foglalt
        // memóriaterülete van, akkor azoknak is, amelyeket
        // egy másik sztring alapján inicializálunk:
        //   Sztring s1 = "alma";
        //   Sztring s2 = s1;      <- az ilyennek
        // Általánosságban: ha van destruktor, akkor kell copy ctor.
        Sztring(Sztring const & orig) {
            hossz = orig.hossz;
            adat = new char[hossz+1];
            strcpy(adat, orig.adat);
        }

        // Ha két sztring közötti értékadást csinálunk, akkor
        // annak nem szabad az adattagok közti értékadásnak lennie,
        // mert akkor a pointer is másolódik (és lenne egy memleak
        // meg közös tömb). Ezért saját operator= kell, ami
        // pl. ilyenkor hívódik:
        //   Sztring s1 = "alma", s2 = "korte";
        //   s2 = s1;             <- ilyenkor
        // Érdemes ezt összehasonlítani a fenti sorral! Nem
        //   Sztring s2 = s1;
        // hanem
        //   s2 = s1;
        // A Sztring-gel kezdődő sor konstruktor, az anélküli pedig
        // értékadó operátor.
        // Általában: ha kellett dtor, akkor kelleni fog op= is.
        // Egyébként op= összerakható a dtor-ból és a copy ctor-ból.
        Sztring & operator=(Sztring const & orig) {
            if (this != &orig) {
                delete[] adat;
                hossz = orig.hossz;
                adat = new char[hossz+1];
                strcpy(adat, orig.adat);
            }
            return *this;
        }

        size_t size() const {
            return hossz;
        }

        char const & operator[] (size_t idx) const {
            return adat[idx];
        }

        char & operator[] (size_t idx) {
            return adat[idx];
        }

        // Sztringek összefűzése. Semmi különös, csak dinamikus és
        // figyelni kell a méretre. Egy fontos dolog, hogy a
        //   Sztring uj;
        // sorban, alapértelmezett konstruktorral létrehozott Sztring
        // karaktertömbjét törölni kell (következő sorban), különben
        // memóriaszivárgás lenne.
        // A lokális változó (uj) visszatéréskor megszűnik, előtte
        // viszont az érték típusú visszatérési érték miatt lemásolódik
        // a másoló konstruktorral. Ezt a másolást általában a fordítók
        // ki szokták optimalizálni, így nem kell attól tartanunk, hogy
        // ez lassú lenne.
        Sztring operator+(Sztring const & rhs) const {
            Sztring uj;
            delete[] uj.adat;
            uj.hossz = this->hossz + rhs.hossz;
            uj.adat = new char[uj.hossz + 1];
            strcpy(uj.adat, this->adat);
            strcat(uj.adat, rhs.adat);
            return uj;
        }
};

std::ostream & operator<<(std::ostream & os, const Sztring & s) {
    for (size_t i = 0; i != s.size(); ++i)
        os << s[i];
    return os;
}

int main() {
    Sztring a = "alma";
    Sztring b = "fa";
    Sztring c = "x";

    c = a+b;        // c.operator=( a.operator+(b) )

    std::cout << c;

    return 0;       // c, b, a dtor
}