Konstruktor (objektově orientované programování)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 28. června 2016; kontroly vyžadují 22 úprav .

V objektově orientovaném programování je konstruktor třídy (z anglického konstruktor  ) speciální blok instrukcí, který se volá při vytvoření objektu.

Přiřazení konstruktoru

Jednou z klíčových vlastností OOP je zapouzdření : vnitřní pole třídy nejsou přímo přístupná a uživatel může pracovat s objektem jako celkem pouze prostřednictvím veřejných ( public) metod. Každá metoda by měla být ideálně navržena tak, aby objekt, který je ve stavu "platný" (to znamená, když je splněna třída invariant ), byl také v platném stavu, když je metoda vyvolána. A prvním úkolem konstruktoru je převést pole objektu do takového stavu.

Druhým úkolem je zjednodušit používání objektu. Objekt není „ věc sama o sobě “, často musí vyžadovat nějaké informace od jiných objektů: například objekt File, když je vytvořen, musí obdržet název souboru. To lze také provést pomocí metody:

soubor soubor ; soubor . otevřít ( "in.txt" , Soubor :: omRead );

Ale je pohodlnější otevřít soubor v konstruktoru: [1]

Soubor soubor ( "in.txt" , Soubor :: omRead );

Typy konstruktorů

Různé programovací jazyky představují několik druhů konstruktorů:

  • konstruktor s parametry;
  • výchozí konstruktor , který nebere žádné argumenty;
  • pojmenovaný konstruktor – funkce, která předpokládá explicitní volání jménem, ​​které funguje jako konstruktor
  • kopírovací konstruktor  - konstruktor, který přebírá jako argument objekt stejné třídy (nebo odkaz z něj);
  • konverzní konstruktor - konstruktor, který přebírá jeden argument (tyto konstruktory lze volat automaticky pro převod hodnot jiných typů na objekty této třídy).
  • konstruktor přesunu ( specifický pro C++11 )
třída Komplex { veřejnost : // Výchozí konstruktor // (v tomto případě také konverzní konstruktor) Komplexní ( double i_re = 0 , double i_im = 0 ) : re ( i_re ), im ( i_im ) {} // Komplexní kopírovací konstruktor ( const Complex & obj ) { re = obj . re ; im = obj . im ; } soukromý : dvojitý re , im ; };

Konstruktor s parametry

Konstruktory, které přebírají jeden nebo více argumentů, se nazývají parametrizované. Například:

třídní příklad { int x , y ; veřejnost : příklad (); Příklad ( int a , int b ); // parametrizovaný konstruktor }; Příklad :: Příklad () { } Příklad :: Příklad ( int a , int b ) { x = a ; y = b ; }

Parametrizovaný konstruktor lze volat explicitně nebo implicitně, například:

Příklad e = Příklad ( 0 , 50 ); // explicitní volání Příklad e ( 0 , 50 ); // implicitní volání

Výchozí konstruktor

Konstruktor bez požadovaných argumentů. Používá se při vytváření polí objektů, které se nazývají k vytvoření každé instance. Při absenci explicitního výchozího konstruktoru je jeho kód generován kompilátorem (což se samozřejmě neodráží ve zdrojovém textu).

Pojmenovaný konstruktor

Kopírovat konstruktor

Konstruktor, jehož argument je odkaz na objekt stejné třídy. Používá se v C++ k předávání objektů funkcím podle hodnoty .

Kopírovací konstruktor je většinou potřeba, když má objekt ukazatele na objekty alokované na haldě . Pokud programátor nevytvoří kopírovací konstruktor, pak kompilátor vytvoří implicitní kopírovací konstruktor, který zkopíruje ukazatele tak, jak jsou , tj. nedochází ke skutečnému kopírování dat a dva objekty odkazují na stejná data na hromadě. V souladu s tím pokus o změnu „kopie“ poškodí originál a volání destruktoru pro jeden z těchto objektů s následným použitím druhého povede k přístupu do oblasti paměti, která již programu nepatří.

Argument musí být předán odkazem , nikoli hodnotou . To vyplývá z kolize: při předávání objektu hodnotou (zejména při volání konstruktoru) je nutné objekt zkopírovat. Ale abyste mohli kopírovat objekt, musíte zavolat konstruktor kopírování.

Konverzní konstruktor

Konstruktor, který má jeden argument. Určuje převod typu svého argumentu na typ konstruktoru. Tento typ konverze se implicitně použije pouze v případě, že je jedinečný.

Uživatelsky definovaný typ konverze může mít jednu ze dvou forem: - z třídy typu C na jakýkoli typ T, pro který musí mít C C::operátor T() - z libovolného typu T na třídu typu C, pro kterou C musí mít C::C(T) (nebo C::C(T&) nebo C::C(T&&))

Pokud jsou ve výrazu povoleny oba tyto případy, dojde k nejednoznačnosti a chybě kompilace.

Pokud je konstruktor (nebo operátor T()) označen explicitním klíčovým slovem, pak se taková konverze typu použije pouze v případě, že existuje explicitní operace přetypování tvaru (T)C nebo static_cast<T>C. Pokud zde není explicitní slovo, pak může překladač vložit takový převod i implicitně, například při volání funkce f(T arg) ve tvaru f(C).

Konstruktor přesunu

C ++11 zavádí nový typ nekonstantních referencí nazvaný rvalue  reference a označovaný jako T&&, a nový druh konstruktoru — move konstruktory .  Konstruktor přesunu bere jako vstup hodnotu nekonstantní reference na objekt třídy a používá se k přenosu vlastnictví prostředků tohoto objektu. Konstruktory přesunu byly vynalezeny, aby vyřešily ztrátu efektivity spojenou s vytvářením dočasných objektů.

Virtuální konstruktor

Konstruktor není virtuální ve smyslu virtuální metody  - aby mechanismus virtuálních metod fungoval, je potřeba spustit konstruktor, který automaticky nastaví tabulku virtuálních metod tohoto objektu.

"Virtuální konstruktory" se týkají podobného, ​​ale odlišného mechanismu, který se vyskytuje v některých jazycích, jako je Delphi , ale ne C++ a Java . Tento mechanismus vám umožňuje vytvořit objekt jakékoli dříve neznámé třídy za dvou podmínek:

  • tato třída je potomkem nějaké předdefinované třídy (v tomto příkladu je to třída TVehicle);
  • na celé dědičné cestě od základní třídy k vytvořené se řetězec redefinic nepřerušil. Při přepisování virtuální metody vyžaduje syntaxe Delphi klíčové slovo overload, aby mohly vedle sebe existovat staré a nové funkce s různými signaturami, overridebuď k přepsání funkce, nebo reintroducek definování nové funkce se stejným názvem – to druhé není povoleno.
type TVehicle = konstruktor třídy Create ; virtuální ; konec ; TAutomobile = konstruktor třídy ( TVehicle ) Create ; přepsat ; konec ; TMotorcycle = class ( TVehicle ) konstruktor Create ; přepsat ; konec ; TMoped = class ( TMotorcycle ) // přerušení řetězce předefinování - spuštění nového Create konstruktor Create ( x : integer ) ; znovu zavést ; konec ;

Do jazyka je zaveden tzv. typ třídy ( metaclass ). Tento typ může mít jako hodnotu název libovolné třídy odvozené od TVehicle.

typ CVehicle = třída TVehicle ; _

Tento mechanismus vám umožňuje vytvářet objekty jakékoli dříve neznámé třídy odvozené od TVehicle.

var cv : CVehicle ; v : TVehicle ; cv := TAutomobil ; v := cv . vytvořit ;

Všimněte si, že kód

cv := TMoped ; v := cv . vytvořit ;

je nesprávná - směrnice reintroducepřerušila řetězec přepisování virtuální metody a ve skutečnosti bude zavolán konstruktor TMotorcycle.Create(což znamená, že bude vytvořen motocykl, nikoli moped!)

Viz také Továrna (designový vzor)

Syntaxe

C++

Název konstruktoru se musí shodovat s názvem třídy. Je povoleno více konstruktorů se stejným názvem, ale různými parametry .

Příklad class ClassWithConstructor { veřejnost : /* Inicializace vnitřního objektu pomocí konstruktoru */ ClassWithConstructor ( parametr float ) : objekt ( parametr ) {} /* volání konstruktoru AnotherClass(float); */ soukromý : Objekt AnotherClass ; };

Python

V Pythonu je konstruktorem metoda třídy s názvem __init__. Také nezapomeňte, že první argument jakékoli metody musí být ukazatel na kontext třídy self.

Příklad třída ClassWithConstructor : def __init__ ( self ): """Tato metoda je konstruktor.""" pass

Ruby

Jazyk Ruby používá speciální metodu k nastavení objektu do původního konzistentního stavu initialize.

Příklad class ClassWithConstructor def initialize print 'Tato metoda je konstruktor.' konec konec

Delphi

V Delphi , na rozdíl od C++ , je konstruktor deklarován pomocí klíčového slova constructor. Název konstruktoru může být jakýkoli, ale doporučuje se pojmenovat konstruktor Create.

Příklad TClassWithConstructor = veřejný konstruktor třídy Create ; konec ;

Java

Některé rozdíly mezi konstruktory a jinými metodami Java :

  • konstruktory nemají návratový typ (ve skutečnosti jej vždy vracejí);
  • konstruktory nelze volat přímo (je třeba použít klíčové slovo new);
  • konstruktory nemohou mít modifikátory synchronized, final, abstracta native;static
Příklad public class Příklad { private int data ; // Výchozí konstruktor, data jsou inicializována na 1, když je vytvořena instance třídy Example public Example () { data = 1 ; } // Přetížení konstruktoru public Příklad ( int input ) { data = input ; } } // kód ilustrující vytvoření objektu konstruktorem popsaným výše Příklad e = new Example ( 42 );

JavaScript

V JavaScriptu je konstruktor běžnou funkcí používanou jako operand operátoru new. Klíčové slovo se používá k odkazování na vytvořený objekt this.

Specifikace ECMAScript 6 však přidala prototyp syntaktického wrapperu, který má takové vlastnosti OOP , jako je dědičnost, a také malý seznam požadovaných metod, například: toString().

Příklad function Příklad ( initValue ) { this . myValue = initValue ; } příklad . prototyp . getMyValue = function () { return this . mojeHodnota ; } //třída třídy ES6 Příklad { konstruktor () { konzola . log ( 'konstruktor' ); } } // kód ilustrující vytvoření objektu konstruktorem popsaným výše var exampleObject = new Example ( 120 );

Visual Basic .NET

Konstruktory ve Visual Basic .NET používají běžnou deklarační metodu s názvem New.

Příklad Class Foobar Private strData jako řetězec ' Konstruktor Public Sub New ( ByVal someParam As String ) strData = someParam End Sub End Class ' nějaký kód ' ilustrující vytvoření objektu výše uvedeným konstruktorem Dim foo As New Foobar ( ".NET" )

C#

Příklad class MyClass { private int _cislo ; soukromý řetězec _řetězec ; public MyClass ( int num , string str ) { _number = num ; _string = str ; } } // Kód ilustrující vytvoření objektu konstruktorem popsaným výše příklad MyClass = new MyClass ( 42 , "string" );

Eiffel

V Eiffelovi se rutiny, které inicializují objekty, nazývají procedury vytváření . Postupy tvorby jsou poněkud podobné konstruktorům a poněkud odlišné. Mají následující vlastnosti:

  • Procedury vytváření nemají žádný explicitní typ výsledku návratu (jak je definováno procedurou [Poznámka 1] ).
  • postupy tvorby jsou pojmenovány (názvy jsou omezeny na platné identifikátory);
  • postupy tvorby jsou specifikovány jmény v textu třídy;
  • procedury vytváření mohou být volány přímo (jako normální procedury) k reinicializaci objektů;
  • každá efektivní (tj. konkrétní, nikoli abstraktní) třída musí (explicitně nebo implicitně) specifikovat alespoň jeden postup vytváření;
  • procedury vytváření jsou zodpovědné za uvedení nově inicializovaného objektu do stavu, který splňuje invariant třídy [Poznámka 2] .

Ačkoli je vytváření objektu předmětem některých jemností [Poznámka 3] , vytvoření atributu s deklarací typu x: Tvyjádřenou jako příkaz vytvoření create x.makesestává z následující sekvence kroků:

  • vytvořit novou přímou instanci typu T[Poznámka 4] ;
  • spustit proceduru vytvoření makepro nově vytvořenou instanci;
  • připojte nově vytvořený objekt k entitě x.
Příklad

První pasáž níže definuje třídu POINT. Postup makeje zakódován za klíčovým slovem feature.

Klíčové slovo createpředstavuje seznam procedur, které lze použít k inicializaci instancí třídy. V tomto případě seznam obsahuje default_createproceduru s prázdnou implementací zděděnou z třídy ANYa proceduru makes implementací v samotné třídě POINT.

class POINT vytvořit default_create , make Vlastnosti make ( a_x_value : REAL ; a_y_value : REAL ) do x := a_x_value y := a_y_value end x : REAL -- X souřadnice y : REAL -- Y souřadnice ...

Ve druhé pasáži má třída, která je klientem třídy , POINTdeklarace my_point_1typu . my_point_2POINT

V kódu podprogramu my_point_1je vytvořen se souřadnicemi (0,0; 0,0). Protože v příkazu vytvoření není uvedena žádná procedura vytvoření, použije se procedura default_createzděděná z třídy ANY. Stejný řádek by mohl být přepsán jako create my_point_1.default_create. createV příkazech create (tj. příkazech s klíčovým slovem ) lze použít pouze procedury určené jako procedury create .

Následuje instrukce create for my_point_2, která nastavuje počáteční hodnoty souřadnic my_point_2.

Třetí instrukce provede normální volání procedury makepro reinicializaci instance připojené k my_point_2jiným hodnotám.

my_point_1 : POINT my_point_2 : POINT ... create my_point_1 create my_point_2 . make ( 3.0 , 4.0 ) my_point_2 . udělat ( 5.0 , 8.0 ) ...

Studená fúze

Příklad

Je třeba poznamenat, že v ColdFusion neexistuje žádná metoda konstruktoru . Běžnou metodou mezi komunitou programátorů ColdFusion je volání metody ' ' initjako pseudokonstruktoru.

<cfcomponent displayname = "Sýr" > <!--- vlastnosti ---> < proměnné cfset . cheeseName = "" / > <!--- pseudo-constructor ---> <cffunction name = "init" returntype = "Cheese" > <cfargument name = "cheeseName" type = "string" povinné = "true" / > < proměnné cfset . cheeseName = argumenty . cheeseName / > <cfreturn this / > </cffunction> </cfcomponent>

PHP

Příklad

V PHP (od verze 5) je konstruktor metoda __construct(), která je automaticky volána klíčovým slovem newpo vytvoření objektu. Obvykle se používá k provádění různých automatických inicializací, jako je inicializace vlastností. Konstruktory mohou také převzít argumenty, v takovém případě, když je zadán výraz new, musí být formální parametry předány konstruktoru v závorkách.

class Osoba { private $name ; function __construct ( $jméno ) { $toto -> jméno = $jméno ; } function getName () { return $this -> jmeno ; } }

Konstruktor v PHP verze 4 (a dřívější) je však metoda třídy se stejným názvem třídy.

class Osoba { private $name ; function Osoba ( $jméno ) { $this -> jméno = $jméno ; } function getName () { return $this -> jmeno ; } }

Perl

Příklad

V Perlu musí konstruktor použít funkci bless na nějakou proměnnou (obvykle hash odkaz):

Příklad balíčku ; sub new { moje $třída = posun ; moje $já = {}; return požehnat $self , $class ; } 1 ;

Ale to je minimální základní možnost, existuje mnoho pokročilejších metod, od pole použití po Moose.

Zjednodušené konstruktory (s pseudokódem )

Konstruktory jsou vždy součástí implementace tříd. Třída (v programování) popisuje specifikace základních charakteristik množiny objektů, které jsou členy třídy, nikoli individuální charakteristiky některého z objektů. Podívejme se na jednoduchou analogii. Vezměme si jako příklad množinu (nebo třídu, abychom použili jeho obecnější význam) studentů z určité školy. Máme tedy:

student třídy { // popis studentské třídy // ... jiný kód ... }

Třída Student je však pouze obecnou šablonou (prototypem) pro naše studenty. Pro jeho použití programátor vytvoří každého studenta jako objekt nebo entitu ( implementaci ) třídy. Tento objekt je skutečný kus dat v paměti, jehož velikost, vzor, ​​vlastnosti a (do určité míry) chování jsou definovány definicí třídy. Obvyklým způsobem vytváření objektů je volání konstruktoru (třídy mohou mít obecně samostatné konstruktory). Například,

student třídy { Student(String studentName, String Address, int ID) { // ... zde ukládáme vstupní data a další interní pole ... } //... }

Viz také

Poznámky

  1. Eiffelovy podprogramy jsou buď procedury nebo funkce . Procedury nemají žádný návratový typ. Funkce mají vždy návratový typ.
  2. Protože musí být splněn i invariant zděděné třídy (tříd), není zde žádný povinný požadavek na volání nadřazených konstruktorů.
  3. Úplná specifikace je obsažena v normách ISO/ECMA pro programovací jazyk Eiffel, které jsou dostupné online. [2]
  4. Eiffelův standard vyžaduje, aby pole byla inicializována při prvním přístupu, vč. není nutné je inicializovat s výchozími hodnotami při vytváření objektu.

Odkazy

  1. To samozřejmě vede k určitým technickým potížím – například co se stane, když konstruktor vyvolá výjimku ? Vývojář třídy však prostě musí vyhovět požadavkům jazyka a většina programů nevyžaduje podrobnou diagnostiku a automatické opakování chyb.
  2. Dokument popisu Eiffelovy normy ISO/ECMA . Získáno 19. dubna 2009. Archivováno z originálu 16. června 2008.