Virtuálne vs nevirtuálne metódy rubrika: Programování: C/C++
Momentálne v práci programujem najviac v jazykoch, ktoré majú všetky metódy implicitne virtuálne (JS, Typescript).
Ale vo volnom čase používam jazyky, kde máme možnosť výberu medzi virtálnou a nevirtuálnou metódou (F#, C++, C#) v týchto jazykoch, ktoré sa orientujú na rýchlosť sú metódy implicitne ne-virtuálne a keď chceme virtuálnu metódu, treba ju označiť slovom virtual (v F# inak ale to tu nechcem rozoberať). Naopak v Jave sú metódy implicitne virtuálne (okrem privátnych) a keď chceme nevirtuálnu metódu, treba ju označiť ako final.
Virtuálne metódy sú tie pri ktorých dedičnosť a polymorfizmus fungujú tak ako očakávame od objektového jazyka. Inak povedané zatiaľ čo nevirtuálne metódy sa v predkovi len overloadujú (prekrývajú) virtuálne sa overridujú (prepisujú). Pre tých čo nechápu ešte príklad:
struct Parent { virtual void virtualMethod() const { std::cout << "called Parent::virtualMethod" << std::endl; } void nonVirtualMethod() const { std::cout << "called Parent::nonVirtualMethod" << std::endl; } void callVirtualMethod() const { virtualMethod(); } void callNonVirtualMethod() const { nonVirtualMethod(); } }; struct Child : Parent { void virtualMethod() const override { std::cout << "called Child::virtualMethod" << std::endl; } void nonVirtualMethod() const { std::cout << "called Child::nonVirtualMethod" << std::endl; } }; void main() { auto child = Child(); child.callVirtualMethod(); // metoda bola prepisana metodou z potomka takze sa vypise: called Child::virtualMethod child.virtualMethod(); // rovnaky vysledok bude pri priamom volani: called Child::virtualMethod child.callNonVirtualMethod(); // metoda nebola prepisana, ale len prekryta takze sa zavola metoda z predka: called Parent::nonVirtualMethod child.nonVirtualMethod(); // ked ju ale zavolam priamo tak sa vypise: prekryta varianta: called Child::nonVirtualMethod }
Ide o dilemu výkon vs rozšíriteľnosť. Podľa akého kľúča sa rozhodujete či definujete metódu ako virtuálnu? Alebo definujete všetky metódy ako virtuálne a nevirtuálne používate iba vy výnimočných prípadoch? (kritické miesta kde sa šetrí každá milisekunda?). Neni používanie nevirtuálnych metód predčasná optimalizácia?
Metodu nastavím jako virtuální, pokud tento účel jasně vyplývá z návrhu. Rozhodně tedy ne, že jen tak pro jistotu udělám vše virtuální. Prostě musí existovat důvod proč něco dělám. Implicitní volbu za mne udělal tvůrce jazyka. Z tohoto důvodu také reálné dilema výkon vs. rozšiřitelnost nejspíš nikdy nenastane. Mohlo by snad jen u nějaké klíčové metody s extrémně častým voláním v nějaké výkonově kritické sekci.
DOPLNĚNÍ: Nepřidání klíčového slova "virtual" není optimalizací. Naopak právě jeho přidání všude by bylo předčasnou optimalizací. I když ne na výkon, ale na rozšiřitelnost.
Komentáře
- xxar3s : Máte nejaké jednoduché pravidlo (alebo sadu pravidiel) podľa ktorého sa viete jednoznačne rozhodnúť či metódu označíte za virtuálnu? Alebo sa rozhodujte len intuitívne? — 9.1.2021
- vit.herman : Ano. Musím mít konkrétní důvod a předpoklad, že danou metodu skutečně budu já nebo uživatel knihovny rozšiřovat. Pokud udělám třeba setter setA(int a), chci, aby nastavil interní atribut "a". A nechci dovolit, aby metodu někdo overridoval a tak mohl (byť omylem) zamezit její základní funkci. A někdy už součástí myšlenky (modelu) je, že nějaká metoda je přímo stvořena pro override. Tu mohu udělat abstraktní nebo pouze virtuální s nějakou implicitní implementací. Ale opět se vracím k tomu, že o důvodech rozhoduje vývojář a samozřejmě záleží na jeho intuici, umění a zkušenostech, zda vznikne pěkný návrh nebo paskvil. Bohužel tuto realitu nezle obejít univerzálnějším pravidlem :-) Mohu s naprostou jistotou poradit jen to, abychom netvořili příliš zjednodušující pravidla typu "uděláme vše virtuální, aby bylo vše rozšiřitelné". V některých jazycích je sice virtual jako default, v některých případech je to ústupek. A nakonec třeba v Javě to považuji za ne zcela ideální návrhový koncept, který byl překonán. — 9.1.2021
Pro plný přístup na Devel.cz se prosím přihlaste:
Nebo se přihlaste jménem a heslem:
Komentáře