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.
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 );Různé programovací jazyky představují několik druhů konstruktorů:
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í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).
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í.
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).
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ů.
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:
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)
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 ; };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.""" passJazyk 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 konecV 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 ;Některé rozdíly mezi konstruktory a jinými metodami Java :
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 );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" )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:
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ů:
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 ) ...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>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 ; } }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.
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 ... } //... }