Polymorfismus (programování)

Z Wikipedie, otevřené encyklopedie
Skočit na: Navigace, Hledání

Polymorfismus je vlastnost programovacího jazyka, objektově orientovaného programování (OOP), která umožňuje:

  • jednomu objektu volat jednu metodu s různými parametry (ad-hoc polymorfismus)
  • objektům odvozených z různých tříd volat tutéž metodu se stejným významem v kontextu jejich třídy, často pomocí rozhraní
  • přetěžování operátorů neboli provedení rozdílné operace v závislosti na typu operandů (parametrický polymorfismus)

Polymorfismus obecněji[editovat | editovat zdroj]

Polymorfismus je vlastnost programovacího jazyka, speciálně v objektově orientovaném programování, která umožňuje objektům volání jedné metody se stejným jménem, ale s jinou implementací. V jiném kontextu (než OOP) se tento druh polymorfizmu nazývá podtypový, na rozdíl od parametrického polymorfizmu (ve funkcionálním programování), který odpovídá spíš generice (např. v C#) nebo šabloně v OOP (Java, C++).

Funkce, metoda nebo makro (a další syntaktické konstrukce) se dají volat s různými datovými typy. Implementace se liší podle druhu polymorfizmu.

(Podtypový) Polymorfismus dělíme na dva typy: statický a dynamický. Při statickém je v době překladu znám konkrétní typ argumentu a proto překladač vygeneruje volání konkrétní (monomorfní) funkce, která pracuje se správným typem. Dynamický p. vybírá volanou funkci za běhu (tzv. pozdní vazba, late binding), v OOP typicky pomocí tabulky virtuálních metod (TVM). Tato tabulka není programátorovi přímo přístupná a generuje ji překladač. V obou případech se kód funkcí generuje při překladu. Tzv. přetížené funkce (overloading) odpovídají statickému polymorfizmu, ale pro každý typ parametru/-ů generují samostatný kód (viz omezený polymorfizmus dále). Dynamický polymorfizmus potřebuje (v nějaké formě) informace o typech za běhu, proto má časovou a/nebo paměťovou režii. Statický polymorfizmus typy za běhu (při dobrém návrhu jazyka a implementace) v principu nepotřebuje, ale ze šablon/generik vygeneruje několik podobných funkcí.

Příklady: objektový polymorfismus (s virtuálními metodami) je dynamický, šablony nebo generika jsou statického typu. Dynamicky typované interpretované jazyky (Ruby, Python) používají také dynamický polymorfizmus.

Polymorfismus může být dvojího druhu: univerzální (parametr typu může být jakýkoliv), omezený (typ jen z určitého výčtu). Např. funkce maximum – nemůže být nad čímkoliv, jen nad orderable, tj. datovým typem, který lze porovnat na větší, menší. Univerzální typ odpovídá parametrickému polymorfizmu, který lze realizovat jednou funkcí pro všechny typy (za daného omezení). Např. funkce pro délku spojového seznamu nezávisí na typu prvků v seznamu, protože je nevyužívá (a např. prvky jsou schované za pointrem). Omezený polymorfizmus závisí na typu a konkrétní typ si funkce předává jako dodatečný (schovaný) parametr, TVM je realizovaná tímto způsobem.

Pokud si chceme realizovat polymorfizmus (ve formě přetížení) sami, např. při variantních záznamech (union v C), např. pro dvě reprezentace komplexních čísel (pravoúhlou a polární), můžeme ve funkcích využít vnitřně přepínač switch podle tagu reprezentace.

Že je oblast populární a terminologie nejednotná, můžete zjistit porovnáním částí z dědičnosti, přetížení funkce, metoda a dalších.

Příklady[editovat | editovat zdroj]

Parametrický polymorfismus[editovat | editovat zdroj]

Příkladem parametrického (operátorového) polymorfismu jsou šablony v C++. Funkce nemá pevně stanovený typ argumentu, dokáže tak přijmout různé typy. Následující funkce násobí parametry i přesto, že nezná jejich typ, lze ji tak volat s různými typy:

#include <iostream>
 
using namespace std;
template <class T>
T multiply(T x, T y)
{
	return x * y;
}
 
int main()
{
	int res1, x1 = 2, y1 = 4;
	res1 = multiply(x1, y1);
 
	unsigned long res2, x2 = 5, y2 = 10;
	res2 = multiply(x2, y2);
 
	cout << res1 << "\n" << res2;
 
	return 0;
}

Rozhraní[editovat | editovat zdroj]

Mějme v jazyce PHP rozhraní IShape definující metodu getArea(), od které je očekáváno, že bude vracet obsah geometrického útvaru. Dále třídy Triangle a Circle implementující rozhraní IShape. Obě třídy implementují metodu getArea() z rozhraní IShape, ale každá odlišným způsobem. Nakonec definujme funkci printShapeInfo(), která bude v parametru očekávat instanci třídy implementující rozhraní IShape:

interface IShape
{
	public function getArea();
}
 
class Triangle implements IShape
{
	private $a, $b, $c;
 
	public function __construct($a, $b, $c)
	{
		$this->a = $a;
		$this->b = $b;
		$this->c = $c;
	}
 
	public function getArea()
	{
		//výpočet obsahu pomocí Heronova vzorce
		$o = ($this->a + $this->b + $this->c) / 2;
		return sqrt($o * ($o - $this->a) * ($o - $this->b) * ($o - $this->c));
	}
}
 
class Circle implements IShape
{
	private $radius;
 
	public function __construct($radius)
	{
		$this->radius = $radius;
	}
 
	public function getArea()
	{
		return M_PI * $this->radius * $this->radius;
	}
}
 
function printShapeInfo(IShape $shape)
{
	echo 'Instance třídy ', get_class($shape), ', obsah: ', round($shape->getArea(), 2);
}
 
printShapeInfo(new Triangle(5, 10, 12)); //Instance třídy Triangle, obsah: 24.54
echo PHP_EOL;
printShapeInfo(new Circle(10)); //Instance třídy Circle, obsah: 314.16

Přetěžování operátorů[editovat | editovat zdroj]

PHP interpretuje operátor + jako sčítání (jsou-li operandy čísla) nebo jako sloučení polí (jsou-li operandy pole):

$n1 = 5;
$n2 = 4;
$a1 = array('jablka' => 8, 'hrusky' => 5);
$a2 = array('svestky' => 2);
 
// operátorový polymorfismus
var_dump($n1 + $n2); // int 9
var_dump($a1 + $a2); // array('jablka' => 8, 'hrusky' => 5, 'svestky' => 2)

Související články[editovat | editovat zdroj]