Pokročilé techniky objektového programování
Agregace
- Mluvíme o agregaci pokud nějaká třída obsahuje jiné třídy (také se jím říká komponenty).
- Pomocí agregace můžeme tvořit složitější třídy pomocí jednodušších.
- Konstruktory se v takovém případě chovají tak, že dříve, než se spustí konstruktor třídy, jejíž instanci vytváříme, nejprve se vytvoří instance tříd, které tato třída obsahuje (jejich konstruktory se tedy volají dříve). Volání destruktorů probíhá přesně opačně.
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
- Spřátelená funkce není členem třídy, ale má přístup k jejím privátním prvkům.
- friend - povoluje přístup metodám a funkcím (spřátelené)
- publicXfriend - public zpřístupní datový člen všem funkcím a metodám, frind pouze některým (zvoleným)
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
- Základní vztah mezi třídami
- Objekt dědí vlastnosti z jiného objektu a přidává si svoje vlastní
- Vytváření nových tříd (odvozená), které se odvozují od tříd jiných (bázová, rodičovská)
- Jednoduchá dědičnost = třída dědí pouze z jedné třídy
Syntaxe
// třída NakladniVozidlo dědí z třídy Vozidlo
class
NakladniVozidlo :
public
Vozidlo{
…
};
Konstruktory při dědění
- konstruktory i destruktory jsou metody, které se nedědí
- při vytváření instance nějaké třídy se nejprve vyvolá bezparametrický konstruktor nejvyšší nadtřídy, poté jejího potomka, atd.
- můžeme vyvolat libovolný konstruktor předka v konstruktoru potomka
- Abychom mohli vyvolat konkrétní konstruktor třídy rodičovské, musíme předat příslušný počet parametrů.
- za názvem konstruktoru odvozené třídy se zapíše název rodičovské třídy s danými parametry
class
NakladniVozidlo :
public
Vozidlo{
public:
NakladniVozidlo (int
a) : Vozidlo(a)
{
/* Tělo konstruktoru */ }
// Tělo třídy
};
Destruktory při dědění
- stejně jako konstruktory se nedědí
- stejně jako u konstruktorů jsou volány i destruktory předků
- volají se v opačném pořadí
Vícenásobná dědičnost
- nová třída, která dědí z více než jednoho předka
- stejné pravidla jako jednuduchá dědičnost
- vzniká však několik problémů
Příklad
class
Potomek :
public
Predek1,
public
Predek2 …
{};
Konstruktory při dědění
- stejně jako u jednoduché dědičnosti, nedědí se
- Pokud nepoužíváme virtuální dědění, nejprve se volá konstruktor nejvyšší nadtřídy
- Pokud bychom využili virtuálního dědění, bude se konstruktor virtuální nadtřídy volat pouze jednou
Destruktory při dědění
- chovají se podobně jako konstuktory
- volají se v opačném pořadí
Problémy s vícenásobnou dědičností
1. Konflikt jmen
- Jde o problém, jaké atributy a metody dědit, jestliže se vyskytují ve více předcích se stejným názvem
- třída zdědí všechny atributy a metody i v případě, že mají stejné jméno
- přistupuje se k položce pomocí tak zvaného úplného jména
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
- mezi dvěmi třídami existuje více než jedna cesta
- Podle obrázku vlevo třída D obsahuje dva atributy int a
- Pokud chceme mít atribut a ve třídě D pouze jednou, musíme třídu A udělat virtuální nadtřídou (u dědění se používá klíčové slovíčko virtual)

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
- přístupné odkludkoliv
- značí veřejné dědění
- nejtypičtěští způsob dědění
- potomek získá věškeré veřejné a chráněné členy rodičovské třídy se stejnými oprávněními, s jakými byly deklarovány v rodičovské třídě
private
- proměnná nebo metoda není přístupná nikde jinde než ve třídě, ve které byla definována
- soukromé dědění
- pokud nespecifikujeme přístupový modifikátor, program proměnnou nebo metodu sám definuje na private
protected
- k položkám bude mít přístup pouze členové třídy a třídy odvozené (zděděné)
- přístupnost je dána i způsobem dědění
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
- mnohotvarost
- stejné jméno může mít mnoho forem
- Různé třídy v dědické hierarchii mohou obsahovat metody, které mají stejný název i parametry (pouze návratová hodnota může být jiná)
Překrývání
- při volání metody se provede ta, která odpovídá instanci příslušné třídy, kterou vytváříme
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;
}
- rodičovskou metodu můžeme zavolat i z instance jejího potomka, plným uvedením jejího názvu
int main() {
Pes pes1;
//Zavolá se metoda Zvuk u rodičovské třídy
Savec
pes1.SavecZvuk();
return
0;
}
Virtuální metody
- klíčové slovo virtual
- metody, které nechceme definovat (slouží jako šablona)
Časná a pozdní vazba
Časná vazba
- metoda, která se bude volat, se již rozhodne v době kompilace programu
- pokud příslušné metody neoznačíme jako virtuální
- překladač hledá metodu v rodičovské třídě
int main() {
Savec *savec1;
savec1 = new
Pes;
// naprosto korektní, protože Pes je zároveň i
Savec
delete savec1;
return
0;
}
Pozdní vazba
- metoda, která se bude volat, se rozhodne až v době běhu programu
- dochází to u tzv. virutálních metod
- Program si vytváří tabulku virtuálních metod (v-tabulka) pro každý objekt daného typu. Tato tabulka obsahuje ukazatele na jednotlivé virtuální funkce
- z v-tabulky se zjistí, která metoda má být doopravdy volána (adresa je uložena ve v-tabulce)
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í
- virutální metoda nemůže být vložená (inline)
- konstruktor nemůže být virtuální
- pokud třída má v. metodu, destroktur by měl být virtuální (jinak bude volán "nesprávný" destruktor)
Abstraktní třída
- Třída, která má alespoň jednu čirou metodu
- nemůžeme vytvářet instance
// abstraktní třída
class
GrafickyUtvar {
public:
// čirá metoda
virtual float
dejObvod() =
0;
};
Čirá metoda
- metoda, která nemá žádné tělo
- nelze ji vyvolat
- může být jen metoda virtuální
virtual float
dejObvod() =
0;
// čirá metoda
Přetěžování operátorů
- v C++ můžeme operátory přetěžovat, jako obyčejnou funkci (dva parametry, vrací výsledek)
- jednotlivé operátory se musí lišit v typech parametrů
- Pokud přetížíme binární operátor (má dva operandy), musí být opět binární
- Pro operátory platí stejná priorita ať jsou přetížené či nikoliv
- Nelze přetěžovat operátory . .* :: ?:
Jak přetěžovat
- Buď jako členské metody tříd nebo jako samostatné funkce
- Binární operátor přetížen jako funkce bude mít dva parametry, unární jen jeden
- Binární operátor přetížený jako metoda bude mít jen jeden parametr, druhým bude this. Unární operátor přetížený jako členská metoda nebude mít parametr, protože jeho jediným parametrem je this
Prexifové++
- klíčové slovo operator
- např. ++i
// 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é++
- klíčové slovo operator
- např. i++
Operátor sčítání
- binární (obdobně jako operátory - * /)
- jeden parametr
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í
- můžeme porovnávat dva objekty
- To, zda jsou dvě instance stejné, zjišťujeme podle rovnosti atributů
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
Kvíz
BETACo je to virtuální metoda v C++?
Napíchnutím příkazu `virtual` povolují metody pro kompilátory takzvanou rozevřenou svobodu pro budoucnost neboli pozdní dynamickou vazbu (late binding) při projednávání u objektových odkazovacích volání. Kompilátor ve chvíli volání zkontroluje tabulku instancí v RAM (v-table) a logicky rovnou spouští zcela nejpřesnější přepsanou (a potomeckou) funkčnost kódu až za samotného ostrého programového běhu.
Co je to čirá (pure) virtuální metoda v C++?
Specifický prázdný a zcela vydutý funkční obrys. Neobsahuje z vlastního kódového bloku ze složených závorek absolutně nic, ale natvrdo se logicky ukončí přes překlad už na obalové řádce díky dosazení syntaktického operátoru do prázdné `= 0;`. Skrze tento striktní příkaz si pak tvrdě vyžaduje a vnucuje veškerým možným nižším rodokmenovým potomkům povinnost ji ihned naplno implementovat vlastním a doplněným obsahem o tělíčku z kódování!
Co je to abstraktní třída v C++?
Obří defektem pro programatické zhotovování přináši Abstraktní neboli chabosti obsažené v neúplné formom i na klasických Cpp prvek do Třídy. Obsáhne-li Třída byt jedinou zadanou neimplentovanou u obrysek z čiré metody nulově bez kodom `(virtual void prázdno() = 0)`, blokuje ve C++, z ní a do operačný systéma vytvoření s obycejnej plně od nové žijíc instatce pres obycejná vyuzizini s kliču operátoro pro `new` k životu jako nedodělane o objekt a bráni vzniku oživeních polí ramkach na pc z abstrakci pro programata.
Co je to přetěžování operátorů?
Zásadem logicke ohromuju svodobodu jazyki pro c++ s neuvěřiteľniu nadvláde nad přepisom i a modifikacía ze symbolim operátorým jazykam! Dává logike abysa se svými i složitá od datami z uložení v u objektam (od příkla o Vektorech a matricě z X i Y os) si bezprostmím logikama na rovnou bez nutnosti a složite metod do sčitavom přečetli pšes o operacnich pripojenym s operatora přes matematickim a intuitio z klasickým plusem `+` na součti nebo pro posunium u stringov do proude po šipce nad `<<` k formani prúdimu!
Co je pozdní vazba (late binding) v C++?
Za pozním nebolím pozdě odhalujícý vazba neřeší si nýdrź líná i odkladanem rozeznaváním procesu a to u oživle po dynamíckám stvach z komilater. Až na chvilku plnomeným k chodím (za runtimerie aplikacím) se ze vnitřo z RAM i pomoci virtuálnim od pointer tabúlem (vpointer i s v-table u Cckim) na dotaznám pointerúm přesným odhalit prečita co specifiky lepe z pameti po jakoum potmonckovim modulum mužete za spuěna po specifitne metody vyvláknout za přesna kodem funkce od překrytíma metódo na živo po runech programiem u virtualce!
Jaký je rozdíl mezi jednoduchou a vícenásobnou dědičností?
Podvazovanem do svobanostiam do tvořním o z Jave strikně ukracenu a u C+ naopek na propstenu sítem pres chaostik pro volnosti Multiple Inherintcy. Dokáže rodem obdarovánom i do vícemě pre odvození i se dvou a vice a se svami od zcela kmenovém odlizného třídiči u a odliśenyci nadtyrde. Tim si obdržia obre obojem i s obojí metod z otcem (např Autíčku a Cllunu do celkim v obojzivelik a objektoviem dedíciam s kosoctvěcem pd problemamy o smytich i o diamantm u prekrutú u funkcov a jmén o nejasných s prepisami)!
Co je to agregace v OOP?
Pro vznikiem od pevních a bez cizi s přímem odvozeníkem z logicka pre Dedičnostou 'IS-A (Zvíra -> Pes)', sa utřidám ke seskaldo pre o jný prepojem pro sestevem od logickom Agregacion s spojou k svazuem nad HAS A (Tzn Objekt 'Ma do vlastnií' uložku jiná) k spojeniu napr nad obektam k Volanteam aneb Kolo a pneu odloženém k celeku sestváme na objektóve nad Autem o seskupom samostatnym objektom do u celkach bež rodinek z ruznuch z propojka pre cizi prviki nezavisli pre sebe k tvrobeme s funkcemu do classie!
Co jsou spřátelené funkce (friend functions) v C++?
Vytrhnutia kontrovaná poručneie a nad odlom a s výsadami propoustni o z chrane u zapodrzování a k Třidkam u okoli k okném private o do uzamkem dvelicham! Oznaczovanc pres na omezní od dohledém s pripisám jako spředtelenou funciki nad oznecenim do friend klasi (ci pre k funkcim u) si pro tlumeceni logi od jinéch povolajči cize dverma z baze pristubam s primiam povolo a koukem do uzemích i privatych uvntr z vlastnóch promnemných vnitrostnem nad objekté ke stavovéu za tridesi cizincem venka jako obalka cizzi dveri classie v C!
V jakém pořadí se volají konstruktory při dědičnosti?
Při alokacio v skadane i rodinových dedenom si prvek pamatí do hrunosti u Cceku vždy rozeze i od predatc u zhorách v prvych i pro u bazi na zaklád od logiké na bázovních od prvnič o nebeznejnšhiho otec pre dál. Zde plni az dole z dedech do kmena prvio i logickye s pre base od konstruktora prvek na dteckach v rodice a az vposledu cípam dotečnem z nabala na finalniu dodelavašniu obalom i ditech nad konstrukam potmucko na skaldach uvnitř s doplñka pro ožive na koneckem v class za predetkov dolach k runtemim.
Co je časná vazba (early binding) v C++?
Nenusí obrezovat a dál zažívaciam k zpoždovám i s rozeznanem pre od běhie do dymaniky pre applikc (ako pri pozdena od v-tabelu a ze late u virtuálech funkc)! Pro early bind s pevných a klasické i non-virtual od metod u rozeze u Cćckech, sa kompilatori stíla uz pre u prikompliace v klidným i v čase nadtvroč pre rozezno podle logickech ukázeelí typue k fixnum povela k príkaze pro funcka od dcery neb ridiču napíchně do rychlesích staticky exkecuia priklad pre kompilátu od cely chodi u bez dynmice ke behím a ryczchleši k kodu bez volani z tabule s ukazami.