Cvičení 7

Dědičnost. Runtime polymorfizmus. Slicing.

Úloha

Knihovna

Hierarchie tříd

Dědičnost

- metody určené k předefinování jsou virtual
class Base{
  int dataBase;
public:
  Base(int data):dataBase(data){}
  virtual void method(){
    cout << dataBase << endl;
  }
};
class Derived : public Base {
  string dataDerived;
public:
  Derived(int dataBase, string dataDerived):
    Base(dataBase), dataDerived(dataDerived){ }

  void method() override{
    Base::method();
    cout << dataDerived << endl;
  }
};
Derived d(1, "x"); d.method();
Ř. 9, "public": předek je viditelný zvenku
Ř. 15, "override": virtual a override jsou zde nepovinné

Virtuální volání

Volání metody odvozené třídy přes ukazatel na předka

#include<memory>
class Base{
  virtual void method() = 0;
  ...
};

class Derived : public Base{
  void method() override {
     ...
  }
};
unique_ptr<Base> b
  = make_unique<Derived>();

b->method();
Ř. 15, "(); ()": zavolá Derived::method

Virtuální volání

Base b;
Derived d;

diagram virtual

Nepolymorfní vektor

vector<Base> vec_base;

diagram polymorfní vector

Slicing

vector<Base> vec_base;
vec_base.push_back(Derived());

Base b = Derived();

diagram slicing

Zákaz kopírování

class Base{
  Base(const Base&) = delete;
  Base& operator=(const Base&) = delete;
public:
  Base(){}
  ...
};

Abstraktní předek

class Base{
  virtual void method() = 0;
  ...
};

class Derived : public Base{
  void method() override {
    ...
  }
};
Ř. 1, "Base": abstraktní třída
Ř. 2, "0": čistě virtuální metoda

Polymorfní vektor

vector<unique_ptr<Base> > vec_ptr_base;

diagram polymorfní vector

Kopírování

Z unique_ptr nelze tvořit kopii:

void m(unique_ptr<Base> p){
  unique_ptr<Base> p2 = p; 
}

void m(unique_ptr<Base> p){
  unique_ptr<Base> p2 =
    make_unique<Base>(p); 
}
Ř. 2, "p": unique_ptr nelze kopírovat
Ř. 7, ")": slicing!

Klonování

class Base{
public:
  virtual unique_ptr<Base> clone() const = 0;
};
class Derived : public Base{
public:
  unique_ptr<Base> clone() const override{
    return make_unique<Book>(*this);
  }
};
void m(unique_ptr<Base> p){
  unique_ptr<Base> p2 = p->clone();
}
Ř. 8, ")": naalokuje objekt správného typu

Virtuální destruktor

class Base{
  virtual ~Base(){}
};
class Derived : public Base{
};


unique_ptr<Base> p = make_unique<Derived>();
Ř. 2, "{} {}": prázdný virtuální destruktor
Ř. 4, "Base": v odvozené třídě automaticky virtuální

Test na typ

Jak zjistit, zda je objekt daného typu?

Base* b = ...
Derived* d = dynamic_cast<Derived*>(b);
if(d){
  ...
}
Ř. 2, "*": pokud b neukazuje na objekt typu Derived, vrátí nullptr

Při použití na reference nelze vrátit nullptr:

Base& b = ...
Derived& d = dynamic_cast<Derived&>(b);
Ř. 2, "&": pokud b neukazuje na objekt typu Derived, vyhodí výjimku bad_cast