1. Ismétlés: kompatibilitás

void invertal(Alakzat& alakzat) {
    uint32_t regiszin = alakzat.get_szin();
    uint32_t ujszin = szin_invertal(regiszin);
    alakzat.set_szin(ujszin);
}

int main() {
    Teglalap t1(/* ... */);
    invertal(t1); /* Teglalap& → Alakzat& */
}

2. Ismlétlés: heterogén kollekció

std::vector<Alakzat*> alakzatok; // közös tároló

alakzatok.push_back(new Teglalap(0xFF0000FF, Pont(1, 2), 4, 3));
alakzatok.push_back(new Kor(0x00FF00FF, Pont(3, 0), 2));

for (size_t i = 0; i < alakzatok.size(); ++i)
    alakzatok[i]->rajzol();

for (size_t i = 0; i < alakzatok.size(); ++i)
    delete alakzatok[i];

3. Memóriakép

4. Virtuális destruktor

5. Szeletelődés

void kirajzol(TeliAlakzat alakzat) { // hibás
    alakzat.rajzol();
}
  • TeliAlakzat absztrakt
  • elveszítjük a leszármazottra vonatkozó információt
  • TeliAlakzat::TeliAlakzat(TeliAlakzat const& other);

6. Akakzat interfész

class Alakzat {
  public:
    virtual void rajzol() const = 0;
    virtual bool bennevan(Pont p) const = 0;
    virtual void mozgat(Pont ennyivel) = 0;
    virtual ~Alakzat() {}
};

void kirajzol(Alakzat& alakzat) {
    alakzat.rajzol(); // hogy csinálja?
}

7. Vtable

void kirajzol(Alakzat& alakzat) {
    alakzat.rajzol(); // hogy csinálja?
}

Heterogén kollekció osztályban

9. Kivételkezelés?

std::vector<Alakzat*> alakzatok;

alakzatok.push_back(new Teglalap(/* ... */));
alakzatok.push_back(new Kor(/* ... */));

for (size_t i = 0; i < alakzatok.size(); ++i)
    alakzatok[i]->rajzol(); // és ha kivételt dob?

for (size_t i = 0; i < alakzatok.size(); ++i)
    delete alakzatok[i];

10. Naiv megoldás

std::vector<Alakzat*> alakzatok;

alakzatok.push_back(new Teglalap(/* ... */));
alakzatok.push_back(new Kor(/* ... */));

try {
    for (size_t i = 0; i < alakzatok.size(); ++i)
        alakzatok[i]->rajzol();
} catch (...) {
    for (size_t i = 0; i < alakzatok.size(); ++i)
        delete alakzatok[i];
    throw; // újradobjuk
}

for (size_t i = 0; i < alakzatok.size(); ++i)
    delete alakzatok[i];

11. Rajztabla osztály

class Rajztabla {
    std::vector<Alakzat*> alakzatok;
public:
    void hozzaad(Alakzat* uj) { // dinamikusan foglalt
        alakzatok.push_back(uj);
    }
    void rajzol() const {
        for (size_t i = 0; i < alakzatok.size(); ++i)
            alakzatok[i]->rajzol();
    }
    ~Rajztabla() {
        for (size_t i = 0; i < alakzatok.size(); ++i)
            delete alakzatok[i];
    }
};

12. Másolás

class Rajztabla {
    std::vector<Alakzat*> alakzatok;
    Rajztabla(Rajztabla const&); // C++98: private
    Rajztabla& operator=(Rajztabla const&);
public:
    Rajztabla();
    ~Rajztabla();
};
class Rajztabla {
    std::vector<Alakzat*> alakzatok;
public:
    Rajztabla() = default; // C++11: default
    Rajztabla(Rajztabla const&) = delete; // C++11
    Rajztabla& operator=(Rajztabla const&) = delete;
    ~Rajztabla();
};

cast-ok

14. dynamic_cast

  • downcasting-ra való
  • általában nem a legjobb ötlet.
  • csak olyan osztályokra működik, aminek van virtuális függvénye
class Rajztabla {
    std::vector<Alakzat*> a;
public:
    /* ... */
    void set_szin(uint32_t szin) {
        for (size_t i = 0; i < a.size(); ++i) {
           TeliAlakzat* ta = dynamic_cast<TeliAlakzat*>(a[i]);
            if (ta != nullptr)
                ta->set_szin(szin);
        }
    }
};

15. dynamic_cast

Referenciákra:

#include <stdexcept>

void f(Alakzat& a) {
    TeliAlakzat& pa = dynamic_cast<TeliAlakzat&>(a);
}

int main() {
    Teglalap t;
    try {
        f(t);
    } catch (std::bad_cast& x) {
        std::cerr << x.what() << std::endl;
    }
}

16. static_cast

class P {
    Rajztabla r;
public:
    P() {
        r.hozzaad(new Teglalap(/* ... */));
        r.hozzaad(new Kor(/* ... */));
        r.hozzaad(new Kor(/* ... */));
    }

    void set_szin(uint32_t szin) {
        for (int i = 0; i < static_cast<int>(r.meret()); ++i) {
            TeliAlakzat* ta = static_cast<TeliAlakzat*>(r[i]);
            ta->set_szin(szin);
        }
    }
};

17. const_cast

class Rajztabla {
    std::vector<Alakzat*> a;
public:
    /* ... */
    Alakzat const* at(size_t index) const {
        /* ... */
    }
    Alakzat* operator[](size_t index) {
        Alakzat const* pa = this->at(index);
        return const_cast<Alakzat*>(pa);
    }
};

18. Egyéb cast-ok

  • reinterpret_cast:
int x = 0x11223344;
unsigned char* p = reinterpret_cast<unsigned char*>(&x);

for (size_t i = 0; i != sizeof(x); ++i)
    printf("%02x ", p[i]);
  • C cast, (Alakzat*)x: kb. sorban const_cast, static_cast és reinterpret_cast
  • Függvényszerű cast, int(d): C cast egyszavas típusokra

Kivételkezelés

20. Ősosztály szerinti catch

Kor::rajzol() {
    throw std::runtime_error("baj van"); // leszármazottat dobunk
}

int main() {
    Rajztabla rajztabla;
    try {
        rajztabla.rajzol();
    } catch (std::exception& x) { // ősosztály szerint
        std::cerr << e.what() << std::endl;
    }
}

21. Több catch blokk

Kor::rajzol() {
    throw std::runtime_error("baj van");
}

int main() {
    Rajztabla rajztabla;
    try {
        rajztabla.rajzol();
    } catch (std::runtime_error& x) {
        std::cerr << e.what() << std::endl;
    } catch (std::exception& x) {
        std::cerr << e.what() << std::endl;
    }
}

STL kitérő

23. std::exception hierarchia

  • std::exception
    • std::logic_error
      • std::invalid_argument
      • std::out_of_range
      • ...
    • std::runtime_error
      • std::system_error (C++11)
        • ...
      • ...
    • std::bad_alloc
    • std::bad_cast

24. Fájlkezelés az STL-ben

  • #include <fstream>
  • Ősosztályok: std::ostream, std::istream
  • std::ofstream: output file stream
  • std::ifstream: input file stream
std::ostream& operator<<(std::ostream& os, Pont const& p) {
    os << '(' << p.x << ',' << p.y << ')';
    return os;
}

int main() {
    std::cout << Pont(1, 2);
    std::ofstream of("ki.txt");
    of << Pont(1, 2);
}

25. stringstream

  • #include <sstream>
  • std::istringstream
  • std::ostringstream
  • std::stringstream: std::istream és std::ostream!
std::ostream& operator<<(std::ostream& os, Pont const& p) {
    os << '(' << p.x << ',' << p.y << ')';
    return os;
}

int main() {
    std::cout << Pont(1, 2);
    std::ostringstream os;
    os << Pont(1, 2);
    std::cout << os.str() << std::endl; // (1, 2)
}

Többszörös öröklés

27. Többszörös öröklés

class Hallgato { /* ... */ };
class Oktato { /* ... */ };

class Demonstrator : public Hallgato, public Oktato { 
    /* ... */ 
};

28. Diamond öröklés problémája

class Ember { /* ... */ }; // !
class Hallgato : public Ember { /* ... */ };
class Oktato : public Ember { /* ... */ };

class Demonstrator : public Hallgato, public Oktato { // !
    /* ... */ 
};

29. Diamond öröklés megoldása

class Ember { /* ... */ };
class Hallgato : public virtual Ember { /* ... */ }; // !
class Oktato : public virtual Ember { /* ... */ }; // !

class Demonstrator : public Hallgato, public Oktato {
    /* ... */ 
};

30. Rejtett adattag

31. Konstruktorhívás menete

  1. virtuális ősosztályok konstruktorainak hívása
  2. közvetlen ősosztályok konstruktorainak hívása, sorrendben
  3. rejtett adattagok beállítása (vptr, virtuális ős pointere)
  4. adattagok konstruktora, deklaráció szerinti sorrendben
  5. konstruktor törzse

32. Virtuális függvény hívása konstruktorból

#include <iostream>

class Base {
public:
    Base() { 
        this->kiir();
    }
    virtual void kiir() const {
        std::cout << "Base\n";
    }
};

class Derived : public Base {
public:
    void kiir() const override {
        std::cout << "Derived\n";
    }
};

int main() { 
    Derived x;
}

private leszármazás

34. Tartalmazás és delegálás

sormintagyanús
class Stack {
    std::vector<double> adat; // adattag
public:
    void push(double uj) {
        adat.push_back(uj); // végére beszúr
    }
    void pop() {
        adat.pop_back();    // végéről levesz
    }
    double& top() {
        return adat.back(); // utolsó elem
    }
    double const& top() const {
        return adat.back();
    }
    bool empty() const {
        return adat.empty();
    }
};

35. private leszármazás

A stacket a vector felhasználásával implementáljuk.

class Stack : private std::vector<double> { // kifelé nem látszik
public:
    void push(double const& uj) {
        this->push_back(uj); // sajátként elérhető
    }
    void pop() {
        this->pop_back();
    }
    double& top() {
        return this->back();
    }
    double const& top() const {
        return this->back();
    }
    using std::vector<double>::empty; // delegálás
};

36. Ez nem öröklés!

Következik: template

38. Kudos

  • BME EET-nek az InfoC motorért

    • Kohári Zsolt
  • CPPFTW-nek

    • Máté Gábor
    • Szász Márton
  • prog2.cppftw.org