Přetížení funkcí - Function overloading

V některých programovacích jazycích je přetížení funkcí nebo přetížení metod schopnost vytvářet více funkcí stejného jména s různými implementacemi. Volání přetížené funkce spustí konkrétní implementaci této funkce odpovídající kontextu volání, což jednomu volání funkce umožní provádět různé úkoly v závislosti na kontextu.

Například, doTask()a doTask(object o)jsou přetížené funkce. Chcete -li volat druhé, musí být objekt předán jako parametr , zatímco první nevyžaduje parametr a je volán s prázdným polem parametru. Běžnou chybou by bylo přiřadit výchozí hodnotu objektu ve druhé funkci, což by vedlo k nejednoznačné chybě volání , protože kompilátor by nevěděl, kterou ze dvou metod použít.

Dalším příkladem je Print(object o)funkce, která provádí různé akce podle toho, zda tiskne text nebo fotografie. Tyto dvě různé funkce mohou být přetíženy jako Print(text_object T); Print(image_object P). Budeme-li psát přetížené funkce tisku pro všechny objekty náš program bude „print“, jsme se nikdy nebudete muset starat o typu objektu a správná funkce hovoru znovu, volání je vždy: Print(something).

Jazyky podporující přetížení

Mezi jazyky, které podporují přetížení funkcí, patří mimo jiné následující:

Pravidla v přetížení funkcí

  • Stejný název funkce se používá pro více než jednu definici funkce
  • Funkce se musí lišit buď aritou, nebo typy jejich parametrů

Jedná se o klasifikaci statického polymorfismu, ve které je volání funkce vyřešeno pomocí nějakého algoritmu „nejlepší shody“, kde je konkrétní funkce, kterou je třeba volat, vyřešena nalezením nejlepší shody formálních typů parametrů se skutečnými typy parametrů. Podrobnosti o tomto algoritmu se liší jazyk od jazyka.

Přetížení funkcí je obvykle spojeno se staticky napsanými programovacími jazyky, které vynucují kontrolu typu při volání funkcí . Přetížená funkce je ve skutečnosti jen sada různých funkcí, které mají shodný název. Určení, kterou funkci použít pro konkrétní volání, je vyřešeno v době kompilace .

V Javě je přetížení funkcí známé také jako polymorfismus v době kompilace a statický polymorfismus.

Přetížení funkcí by nemělo být zaměňováno s formami polymorfismu, kde se volba provádí za běhu, např. Prostřednictvím virtuálních funkcí , namísto staticky.

Příklad: Přetížení funkce v C ++

#include <iostream>

int Volume(int s) {  // Volume of a cube.
  return s * s * s;
}

double Volume(double r, int h) {  // Volume of a cylinder.
  return 3.1415926 * r * r * static_cast<double>(h);
}

long Volume(long l, int b, int h) {  // Volume of a cuboid.
  return l * b * h;
}

int main() {
  std::cout << Volume(10);
  std::cout << Volume(2.5, 8);
  std::cout << Volume(100l, 75, 15);
}

Ve výše uvedeném příkladu se objem každé komponenty vypočítá pomocí jedné ze tří funkcí s názvem „objem“, přičemž výběr je založen na odlišném počtu a typu skutečných parametrů.

Přetížení konstruktoru

Konstruktory používané k vytváření instancí objektu mohou být v některých objektově orientovaných programovacích jazycích také přetíženy . Protože v mnoha jazycích je jméno konstruktoru předurčeno názvem třídy, zdá se, že může existovat pouze jeden konstruktor. Kdykoli je potřeba více konstruktorů, mají být implementovány jako přetížené funkce. V C ++ , defaultně konstruktéři brát žádné parametry, instance objektových členy s jejich příslušnými výchozími hodnotami. Například výchozí konstruktor pro objekt billboardu restaurace napsaný v C ++ může nastavit tip na 15%:

Bill()
    : tip(0.15), // percentage
      total(0.0)
{ }

Nevýhodou je, že ke změně hodnoty vytvořeného objektu Bill jsou zapotřebí dva kroky. Následující text ukazuje vytváření a změnu hodnot v hlavním programu:

Bill cafe;
cafe.tip = 0.10;
cafe.total = 4.00;

Přetížením konstruktoru by bylo možné při vytváření předat tip a total jako parametry. Toto ukazuje přetížený konstruktor se dvěma parametry. Tento přetížený konstruktor je umístěn ve třídě stejně jako původní konstruktor, který jsme použili dříve. Který z nich se použije, závisí na počtu parametrů poskytnutých při vytváření nového objektu Bill (žádný nebo dva):

Bill(double tip, double total)
    : tip(tip),
      total(total)
{ }

Nyní by funkce, která vytvoří nový Bill objekt, mohla do konstruktoru předat dvě hodnoty a nastavit datové členy v jednom kroku. Následující ukazuje vytváření a nastavování hodnot:

Bill cafe(0.10, 4.00);

To může být užitečné při zvyšování efektivity programu a zkracování délky kódu.

Dalším důvodem přetížení konstruktoru může být vynucení povinných datových členů. V tomto případě je výchozí konstruktor deklarován jako soukromý nebo chráněný (nebo nejlépe odstraněný od C ++ 11 ), aby byl nepřístupný zvenčí. Pro účet výše může být jediným parametrem konstruktoru - protože účet nemá žádné rozumné výchozí hodnoty pro součet - může být součet výše, zatímco tip má výchozí hodnotu 0,15.

Komplikace

Dva problémy interagují a komplikují přetížení funkcí: maskování názvu (kvůli rozsahu ) a implicitní převod typu .

Pokud je funkce deklarována v jednom oboru a pak je ve vnitřním oboru deklarována další funkce se stejným názvem, existují dvě přirozená možná chování při přetížení: vnitřní deklarace maskuje vnější deklaraci (bez ohledu na podpis) nebo obě vnitřní deklarace a vnější deklarace jsou zahrnuty v přetížení, přičemž vnitřní deklarace maskuje vnější deklaraci pouze v případě, že se podpis shoduje. První je převzat v C ++: „v C ++ nedochází k přetížení napříč obory.“ V důsledku toho k získání sady přetížení s funkcemi deklarovanými v různých oborech je potřeba explicitně importovat funkce z vnějšího rozsahu do vnitřního oboru s usingklíčovým slovem.

Implicitní převod typů komplikuje přetížení funkcí, protože pokud typy parametrů přesně neodpovídají podpisu jedné z přetížených funkcí, ale mohou se shodovat po převodu typu, rozlišení závisí na tom, který typ převodu je vybrán.

Ty lze kombinovat matoucím způsobem: Nepřesná shoda deklarovaná ve vnitřním oboru může například maskovat přesnou shodu deklarovanou ve vnějším oboru.

Například pro odvozenou třídu s přetíženou funkcí, která bere a doublenebo an int, pomocí funkce přebírající intze základní třídy v C ++, by člověk napsal:

class B {
 public:
  void F(int i);
};

class D : public B {
 public:
  using B::F;
  void F(double d);
};

Nezahrnutí usingvýsledků do intparametru předaného do Fodvozené třídy převáděné na dvojitou hodnotu a odpovídající funkci v odvozené třídě, nikoli v základní třídě; Zahrnutí usingmá za následek přetížení v odvozené třídě a tedy odpovídající funkci v základní třídě.

Upozornění

Pokud je metoda navržena s nadměrným počtem přetížení, může být pro vývojáře obtížné rozeznat, jaké přetížení je voláno jednoduše čtením kódu. To platí zejména v případě, že některé přetížené parametry jsou typů, které jsou zděděnými typy jiných možných parametrů (například „objekt“). IDE může provést rozlišení přetížení a zobrazit (nebo na něj přejít) správné přetížení.

Přetížení na základě typu může také bránit údržbě kódu, kde aktualizace kódu mohou omylem změnit, jaké přetížení metody zvolí kompilátor.

Viz také

Reference

externí odkazy