20. Pokročilé techniky objektového programování

Agregace

Příklad

#include <iostream>
#define SIZEARRAY 3
using namespace std;

class CA{
    private:
        int m_iNumber;
    public:
        CA():m_iNumber(SIZEARRAY)
            { cout << "Konstruktor CA\n";}
        ~CA(){ cout << "Destruktor CA\n";}
        void SetNumber(int a){m_iNumber = a;}
        int GetNumber(void) const {return m_iNumber;}
};

class CB {
    private:
        CA m_CA[SIZEARRAY];
    public:
        CB() { cout << "Konstruktor CB\n";}
        ~CB(){ cout << "Destruktor CB\n";}

        int Suma(void) const{
        int iSuma = 0;
        for(int i = 0; i < SIZEARRAY; i++)
            iSuma += m_CA[i].GetNumber();

    return iSuma;
};
int main(void) {
    CB a;
    cout << "\n " << a.Suma() << "\n\n" << endl;
    return 0;
}

Vypíše se

Konstruktor CA Konstruktor CA Konstruktor CA
Konstruktor CB
9
Destruktor CB
Destruktor CA Destruktor CA Destruktor CA

Spřátelená funkce a spřátelená třída

Příklad

#include <iostream>

class myclass {
    private:
        int n, d;
    public:
        myclass(int i, int j) { n = i; d = j; }
        // spratelena funkce
        friend int isfactor(myclass ob);
};

int isfactor(myclass ob) {
    if(!(ob.n % ob.d)) return 1;
    else return 0;
}

int main(void) {
    myclass ob1(10, 2), ob2(13, 3);

    if(isfactor(ob1)) cout << "10 je delitelne 2\n";
    else cout << "10 neni delitelne 2\n";

    if(isfactor(ob2)) cout << "13 je delitelne 3\n";
    else cout << "13 neni delitelne 3\n";

    return 0;
}

Musíme si uvědomit, že spřátelená funkce není členem třídy jejímž je přítelem. Není tedy možné volat spřátelenou funkci s využitím jména objektu a tečkového či šipkového operátoru. Přestože tedy spřátelená funkce zná privátní prvky třídy, s níž je spřátelená, může k nim přistupovat pouze přes objekty třídy.

Spřátelená funkce není dědičná. Proto, když základní třída obsahuje spřátelenou funkci, pak tato třída není spřátelena s odvozenou funkcí. Dále platí že spřátelená funkce může být spřátelena s více třídami.

Dědičnost

Jednoduchá dědičnost

Syntaxe

// třída NakladniVozidlo dědí z třídy Vozidlo
class NakladniVozidlo : public Vozidlo{

};

Konstruktory při dědění

class NakladniVozidlo : public Vozidlo{
   public:
      NakladniVozidlo (int a) : Vozidlo(a)
         { /* Tělo konstruktoru */ }
   // Tělo třídy
};

Destruktory při dědění

Vícenásobná dědičnost

Příklad

class Potomek : public Predek1, public Predek2
{};

Konstruktory při dědění

Destruktory při dědění

Problémy s vícenásobnou dědičností

1. Konflikt jmen

class C : public A, public B
{};

int main() {
   C c;
   c.A::nastav(10);
   c.B::nastav(20);
   /* pokud odstraníme následující komentář, překladač
   nás chybou upozorní na nejednoznačnost */

   // c.nastav(0);
}

2. Opakovaná dědičnost
20-opakovana-dedicnost.png

class A // virtuální nadtřída
{ int A; };

class B : virtual public A
{};

class C : virtual public A
{};

class D : public B, public C
{};

3. Konstruktory a destruktory

Direktivy public, private, protected

Public

private

protected

Způsoby dědění

V jazyce C++ existují tři možnosti, jak dědit. Tyto možnosti se liší v závislosti na tom, zda budou jednotlivé metody a atributy v potomkovi viditelné. Tyto způsoby jsou private, public (nejčastější) a protected.

private v předkovi protected v předkovi public v předkovi
private dědění nepřístupné potomkovi private v potomkovi private v potomkovi
protected dědění nepřístupné potomkovi protected v potomkovi protected v potomkovi
public dědění nepřístupné potomkovi protected v potomkovi public v potomkovi

Polymorfismus

Překrývání

int main() {
   //Třídy Savec a Pes mají stejnou metodu Zvuk(),
   ale každá vypíše něco jiného

   Savec savec1;
   Pes pes1;

   savec1.Zvuk();
   // Vypíše se „Zvuk třídy Savec“

   pes1.Zvuk();
   // Vypíše se „Zvuk třídy Pes“

   return 0;
}


int main() {
   Pes pes1;
   //Zavolá se metoda Zvuk u rodičovské třídy Savec
   pes1.SavecZvuk();

   return 0;
}

Virtuální metody

Časná a pozdní vazba

Časná vazba

int main() {
   Savec *savec1;
   savec1 = new Pes;
   // naprosto korektní, protože Pes je zároveň i Savec

   delete savec1;
   return 0;
}

Pozdní vazba

int main() {
   Savec *savec1;
   savec1 = new Pes;
   savec1->Zvuk();
   // Vypíše se „Zvuk třídy Pes“
   // pokud by metody Zvuk nebyly virtuální, vypsalo
   // by se „Zvuk třídy Savec“

   delete savec1;
   return 0;
}

Omezení

Abstraktní třída

// abstraktní třída
class GrafickyUtvar {
   public:
      // čirá metoda
      virtual float dejObvod() = 0;
};

Čirá metoda

virtual float dejObvod() = 0; // čirá metoda

Přetěžování operátorů

Jak přetěžovat

Prexifové++

// v metodě dané třídy by mohlo vypadat následovně:
class Citac{
   private:
      int cislo;
   public:
      Citac():cislo(0){}
      void operator++() { ++this->Cislo; }
};

void main(){
   Citac i;
   // proměnná cislo se v instanci zvýší o 1
   ++i;
}

Postfixové++

Operátor sčítání

Citac operator+(Citac druhy) {
   Citac pomoc;
   pomoc.NastavHodnotu(cislo + druhy.DejHodnotu());

   return pomoc;
}

// Mimo třídu můžeme např. použít:
Citac a, b;
Citac c = a + b;

Operátor porovnání

bool operator==(Citac druhy) {
   if(cislo == druhy.DejHodnotu())
      return true;
   else
      return true;
}

//Mimo třídu můžeme např. použít:
Citac a, b;
if(a == b)

Zdroj

GitHub - keson3948 https://bit.ly/3hxwykq