Mnohotvarost (polymorfizmus) TYPY MNOHOTVAROSTI .............................................................................................................................................................2 PŘETĚŽOVÁNÍ METOD, PŘETĚŽOVÁNÍ OPERACÍ ...............................................................................................................................3 PŘETÍŽENÍ OPERÁTORŮ ..............................................................................................................................................................4 ČASTO PŘETĚŽOVANÉ OPERÁTORY ................................................................................................................... 4 PŘEPISOVÁNÍ ................................................................................................................................................................... 7 VIRTUÁLNÍ METODY ...................................................................................................................................................... 10 SEZNAM OBRÁZKŮ..................................................................................................................................................................12 SEZNAMPROGRAMŮ ...............................................................................................................................................................12
Cílem kapitoly je ukázat možnosti použití mnohotvarosti v objektově orientovaném programování. Klíčové pojmy: Mnohotvarost, přepisování, přetěžování metod a operátorů, virtuální metody. Jsou dvě definice mnohotvarnosti : 1. Mnohotvarost je prostředek, jehož pomocí může být jediný název operace nebo atributu definován na základě více než jedné třídy a může nabývat různých implementací v každé z těchto tříd. 2. Mnohotvarost je vlastnost, jejímž prostřednictvím může atribut nebo proměnná ukazovat (obsahovat identifikátor) na objekty různých tříd v různých okamžicích. Jako příklad mnohotvarosti rozeberme práci s geometrickým tvarem Polygon
Obrázek 1 Různé polygony
Mohli bychom vytvořit třídu Polygon, která by umožňovala pracovat s různými polygony. Třída Polygon by mohla obsahovat operace: Vypočítat plochu – metoda vzítPlochu pro obecný polygon je to složitý algoritmus u některých podtříd to je jednoduchý algoritmus Uvažujeme objekt dvěDTvar 2.11. 2011
kapitola 12
1/12
v době překladu nemusíme vědět, do jaké třídy objekt patří (Tvar, Kruh, Ctverec, Trojúhelník) až za běhu se aktivuje odpovídající algoritmus výpočtu pro zprávu: dvěDTvar.vzítPlochu cílový objekt ”ví“, jak spočítat svou plochu“ Následující diagram znázorňuje odvození tříd Kruh, Čtverec a Trojúhelník ze základní třídy Tvar.
Tvar Nakresli() Smaž() Přesuň() VezmiBarvu() NastavBarvu()
Kruh
Čtverec
Trojúhelník PřeklopSvisle() PřeklopVodorovně()
Obrázek 2 Odvození tříd Kruh, Čtverec, Trojúhelník ze základní třídy Tvar
Typy mnohotvarosti a) přetěžování (overloading) b) přepisování (overriding) c) dynamické vázání a) Přetěžování – názvu nebo symbolu – daný název (symbol) má několik operací (operátorů) definovaných v 1 třídě. Jak se zjistí konkrétní kód? Podle počtu a typu argumentů. b) Přepisování – změna definované metody zadané v nadřízené třídě v některé z jejích podřízených tříd. c) Dynamické vázání – vázání za běhu, pozdní vázání. Technika, jejímž prostřednictvím se konkrétní vykonávaná část kódu zjišťuje až za běhu aplikace.
2.11. 2011
kapitola 12
2/12
Přetěžování metod, přetěžování operací Zavedení stejnojmenných metod lišících se parametry. Příklad: produkt1.snížitCenu() produkt1.snížitCenu(Procento) Přetěžování metod znamená, že dvě, nebo více metod má stejné jméno. Příbuzné činnosti lze realizovat stejnojmennou metodou - přehlednější program. Přetížené metody se mohou lišit typem, nebo počtem argumentů. Program 1 Přetížená metoda pro výpočet absolutní hodnoty
Následující program ilustruje definování a použití přetížené metody abs. Jednotlivé přetížené metody se liší typem argumentu. using System; class Cislo{ public int abs(int n){ return (n >= 0) ? n : -n; } public long abs(long n){ return (n >= 0) ? n : -n; } public double abs(double n){ return (n >= 0) ? n : -n; } } class M{ static void Main(){ Cislo c=new Cislo(); Console.WriteLine("{0}", c.abs(-10)); Console.WriteLine("{0}", c.abs(-1000000000000000L)); Console.WriteLine("{0}", c.abs(-10.01)); Console.ReadLine(); } } Program 2 Přetěžování metod, lišících se počtem argumentů
Následující program uzkazuje použití přetížené metody sum s jedním a se dvěma argumenty. using System; class Soucty{ public double sum(float a) { return a + a; } public double sum(float a, float b) { return a + b; } }
2.11. 2011
kapitola 12
3/12
class M{ static void Main(){ Soucty s = new Soucty(); Console.WriteLine("{0}", s.sum(10)); Console.WriteLine("{0}", s.sum(10, 2)); Console.ReadLine(); } }
Návratový typ není dostatečným rozdílem, který by dovolil přetížit metodu.
Přetížení operátorů Přetížením operátoru je možné definovat novou funkčnost operátoru nad třídami, nebo strukturami, takže lze určité funkce zapisovat pomocí operátorů. Nejužitečnější je tato možnost u takových datových typů, kde je zřejmé, co který operátor dělá. Uživateli se tak nabídne možnost úsporného vyjádření. Přetěžování operátorů se podobá přetěžování metod. Přetížený operátor neztrácí svůj původní význam, ale vzhledem ke třídě, pro kterou je definovaný, získává další významy. Obecný tvar členské funkce operátoru: public static Návratový_typ operator#(seznam_argumentu){ // Operace, která má být provedena }
Návratovým typem bývá často třída, pro kterou je operátor definovaný. Omezení pro přetěžování operátorů Priorita operátoru nemůže být měněna Nemůže být měněn počet operandů Nemůžeme přetížit operátory: . :: .* ? Často přetěžované operátory +, ==, !=
2.11. 2011
kapitola 12
4/12
Program 3 Přetížení operátoru +
V následujícím programu je definovaná třída coord, která přetěžuje operátor + pro sčítání souřadnic dvou bodů. Třída coord má položky: Soukromé celočíselné proměnné x,y pro uchování souřadnic bodu. Dva konstruktory: Bez parametrů, který nuluje hodnoty x,y Se dvěmi parametry, které slouží pro nastavení hodnot souřadnic x,y Metodu getxy, která předává hodnoty souřadnic x,y do volající jednotky odkazem přes parametry. Metodu, která přetěžuje operator +, takže ji je možné použít pro sčítání souřadnic dvou bodů. V Mainu jsou vytvořeny dva body o1, o2 se zadanými souřadnicemi a třetí bod o3, jehož xová souřadnice se bude rovnat součtu x-ových souřadnic bodů o1 a o2 a jehož y-ová souřadnice se bude rovnat součtu y-ových souřadnic bodů o1 a o2. Součet se vytvoří pomocí přetíženého operátoru +. using System; class coord{ int x; int y; // Pretizeni konstruktoru dvojim zpusobem public coord(){x=0;y=0;} // bez inicializatoru public coord(int i,int j){x=i;y=j;} // inicializator public void getxy(ref int i,ref int j){ i=x;j=y; } public static coord operator +(coord ob1,coord ob2){ coord temp = new coord(); temp.x=ob1.x+ob2.x; temp.y=ob1.y+ob2.y; return temp; } }; class Program{ static void Main() { coord o1=new coord(10,10); coord o2=new coord(5, 3); coord o3=new coord(); int i=0,j=0; o3=o1+o2; // soucet dvou objektu - vola operator+() o3.getxy(ref i,ref j); Console.WriteLine("x={0} y={1}",i,j); Console.ReadLine(); } }
2.11. 2011
kapitola 12
5/12
Program 4 Přetížení operátoru ==
Jestliže přetěžujeme operátor ==, musíme též definovat přetížený operátor != . Jestliže tak neučiníme, kompilátor nás na to upozorní. Metoda, která přetěžuje operátor== vrací hodnotu true, když souřadnice objektů, které přebírá jako parametry, jsou stejné. Jinak vrací hodnotu false. Metoda, která přetěžuje operátor!= vrací hodnotu true, když souřadnice objektů, které přebírá jako parametry, nejsou stejné. Jinak vrací hodnotu false. V Mainu jsou vytvořeny dva objekty a pro testování souřadnic je použit přetížený operátor ==. Tímto operátorem se otestuje rovnost obou souřadnic x a y. V případě, že se rovnají, vypíše se text: "Objekty mají stejné souřadnice", jinak se vypíše: "Objekty mají různé souřadnice". using System; class coord{ int x; int y; // Pretizeni konstruktoru dvojim zpusobem public coord(){x=0;y=0;} // bez inicializatoru public coord(int i,int j){x=i;y=j;} // inicializator public void getxy(ref int i,ref int j){ i=x;j=y; } public static coord operator +(coord ob1,coord ob2){ coord temp = new coord(); temp.x=ob1.x+ob2.x; temp.y=ob1.y+ob2.y; return temp; } public static bool operator==(coord ob1,coord ob2){ return ob1.x==ob2.x && ob1.y==ob2.y; } public static bool operator !=(coord ob1, coord ob2) { return ob1.x != ob2.x || ob1.y != ob2.y; } }; class Program{ static void Main(){ coord o1=new coord(10,10); coord o2=new coord(1, 10); if(o1==o2) Console.WriteLine("Objekty mají stejné souřadnice"); else Console.WriteLine("Objekty mají různé souřadnice"); Console.ReadLine(); } }
2.11. 2011
kapitola 12
6/12
Přepisování Přepisování je změna definované metody zadané v základní třídě v některé z jejích odvozených tříd. Přepisované funkce mají stejný počet i typ parametrů na rozdíl od přetěžování. Následující diagram ukazuje přepsání metod Nakresli a Smaž v základní třídě v odvozených třídách, kde je možné pro uvedené činnosti použít jednodušší algoritmy.
Tvar Nakresli() Smaž() Přesuň() VezmiBarvu() NastavBarvu()
Kruh Nakresli() Smaž()
Čtverec Nakresli() Smaž()
Trojúhelník Nakresli() Smaž()
Obrázek 3 Přepsání metod Nakresli a Smaž v odvozených třídách Program 5 Odvození tříd čtverec a obdélník ze základní třídy Tvar
2.11. 2011
kapitola 12
7/12
Tvar Plocha Obvod Vypocty() Vypis()
Čtverec a Vypocty()
Obdélník a,b Vypocty()
Obrázek 4 UML diagram pro základní třídu Tvar a odvozené třídy Ctverec a Obdélník
using System; class Tvar { // základní třída protected double Plocha, Obvod; public Tvar() { Plocha = 0; Obvod = 0; } public void Vypocty() { Console.WriteLine("Vypocty jsou mozne pouze pro objekty tridy Čtverec, nebo Obdélník"); } public void Vypis() { Console.WriteLine("Plocha: {0}", Plocha); Console.WriteLine("Obvod: {0}", Obvod); } }; class Čtverec : Tvar { // první odvozená třída double a; public Čtverec(double x) { a = x; } public void Vypocty() { Plocha = a * a; Obvod = 4 * a; } // přepsání metody Vypocty }; class Obdélník : Tvar { // druhá odvozená třída double a, b; public Obdélník(double x, double y) { a = x; b = y; } // přepsání metody Vypocty
2.11. 2011
kapitola 12
8/12
public void Vypocty() { Plocha = a * b; Obvod = 2 * (a + b); } }; class Program { static void Main() { Tvar u = new Tvar(); Čtverec c1 = new Čtverec(10); c1.Vypocty(); c1.Vypis(); Console.WriteLine(); Obdélník o1 = new Obdélník(1, 2); o1.Vypocty(); o1.Vypis(); Console.WriteLine(); Console.ReadLine(); } }
Vypíše se: Plocha: 100 Obvod: 40 Plocha: 2 Obvod: 6 Program by bylo možné rozšířit o další odvozené třídy a do základní třídy Tvar doplnit vlastnosti, společné pro všechny třídy – například podle následujícího diagram:
Tvar barva_cary barva_vyplne plocha vypis_plochy()
kruh
ctverec
pravtroj
polomer plocha()
strana plocha()
odvesna1 odvesna2 plocha()
Obrázek 5 Doplnění atributů do tříd
2.11. 2011
kapitola 12
9/12
Jediný název (plocha) nabývá různé implementace v různých třídách.
Virtuální metody Virtuální metoda je členská funkce, která je deklarována v rámci základní třídy a je redefinovaná odvozenou třídou. V základní třídě se před jméno virtuální metody uvádí virtual. Virtuální metoda je implementací polymorfismu: „Jedno rozhraní více metod“ Metoda, definovaná jako virtual je určena k tomu, aby byla převážena třídami, které od této třídy dědí. Metoda, která převáží virtuální metodu, používá modifikátor override, který indikuje, že chce nahradit metodu svou vlastní verzí. Modifikátor override je vyžadován, abyste neudělali chybu náhodným převážením metody v případech, kdy jste tak učinit nechtěli. Program 6 Použití virtuální metody
Tento program je modifikací programu Program 5. Zde je metoda Vypocty definovaná jako virtuální. using System; class Tvar { // základní třída protected double Plocha, Obvod; public Tvar() { Plocha = 0; Obvod = 0; } virtual public void Vypocty() { Console.WriteLine("Vypocty jsou mozne pouze pro objekty tridy Čtverec, nebo Obdélník"); } public void vypis() { Console.WriteLine("Plocha: {0}", Plocha); Console.WriteLine("Obvod: {0}", Obvod); } }; class Čtverec : Tvar { // první odvozená třída double a; public Čtverec(double x) { a = x; } override public void Vypocty() { Plocha = a * a; Obvod = 4 * a; } // přepsání metody Vypocty }; class Obdélník : Tvar { // druhá odvozená třída double a, b;
2.11. 2011
kapitola 12
10/12
public Obdélník(double x, double y) { a = x; b = y; } // přepsání metody Vypocty override public void Vypocty() { Plocha = a * b; Obvod = 2 * (a + b); } }; class Program { static void Main() { int co; Tvar u = new Tvar(); Čtverec c1 = new Čtverec(10); Obdélník o1 = new Obdélník(1, 2); Console.WriteLine("Co chces pocitat:"); co = Int32.Parse(Console.ReadLine()); if (co == 1) u = c1; else u = o1; u.Vypocty(); u.vypis(); Console.ReadLine(); } }
Program vypíše: Co chces pocitat: 2 Plocha: 2 Obvod: 6
2.11. 2011
kapitola 12
11/12
Seznam obrázků Obrázek 10 Různé polygony ............................................................................................................... 1 Obrázek 11 Odvození tříd Kruh, Čtverec, Trojúhelník ze základní třídy Tvar ........................... 2 Obrázek 12 Přepsání metod Nakresli a Smaž v odvozených třídách ........................................... 7 Obrázek 13 UML diagram pro základní třídu Tvar a odvozené třídy Ctverec a Obdélník ...... 8 Obrázek 14 Doplnění atributů do tříd ............................................................................................... 9
Seznamprogramů Program 10 Přetížená metoda pro výpočet absolutní hodnoty ..................................................... 3 Program 11 Přetěžování metod, lišících se počtem argumentů ..................................................... 3 Program 12 Přetížení operátoru + ....................................................................................................... 5 Program 13 Přetížení operátoru == ..................................................................................................... 6 Program 14 Odvození tříd čtverec a obdélník ze základní třídy Tvar ......................................... 7 Program 15 Použití virtuální metody ............................................................................................. 10
2.11. 2011
kapitola 12
12/12