Az objektumorientált programozásban az osztálykonstruktor (az angol konstruktor szóból ) egy speciális utasításblokk, amelyet az objektum létrehozásakor hívnak meg.
Az OOP egyik legfontosabb jellemzője a beágyazás : az osztály belső mezői közvetlenül nem érhetők el, és a felhasználó csak az objektum egészével, nyilvános ( public) metódusokon keresztül tud dolgozni. Ideális esetben minden metódust úgy kell megtervezni, hogy egy "érvényes" állapotban lévő objektum (vagyis amikor az osztályinvariáns teljesül ) a metódus meghívásakor is érvényes állapotban legyen. A konstruktor első feladata pedig az, hogy az objektum mezőit ilyen állapotba vigye át.
A második feladat az objektum használatának egyszerűsítése. Egy objektum nem „ önmagában lévő dolog ”, gyakran bizonyos információkat kell kérnie más objektumoktól: például egy objektumnak Filelétre kell hoznia egy fájlnevet. Ez a következő módszerrel is megtehető:
fájl fájl ; fájl . open ( "in.txt" , Fájl :: omRead );De kényelmesebb a fájl megnyitása a konstruktorban: [1]
Fájlfájl ( " in.txt " , Fájl :: omRead );A különféle programozási nyelvek többféle konstruktort kínálnak:
Azokat a konstruktorokat, amelyek egy vagy több argumentumot vesznek fel, paraméterezettnek nevezzük. Például:
osztályos példa { int x , y ; nyilvános : példa (); Példa ( int a , int b ); // paraméterezett konstruktor }; Példa :: Példa () { } Példa :: Példa ( int a , int b ) { x = a ; y = b ; }Egy paraméterezett konstruktort lehet explicit vagy implicit módon meghívni, például:
e példa = példa ( 0 , 50 ); // kifejezett hívás e példa ( 0 , 50 ); // implicit hívásKötelező argumentumok nélküli konstruktor. Objektumtömbök létrehozásakor használatos, amelyek az egyes példányok létrehozására szolgálnak. Explicit alapértelmezett konstruktor hiányában a kódját a fordító generálja (ami természetesen nem jelenik meg a forrásszövegben).
Egy konstruktor, amelynek argumentuma egy azonos osztályba tartozó objektumra való hivatkozás . Használják a C++ -ban objektumok átadására a függvényeknek érték alapján .
A másoláskonstruktorra leginkább akkor van szükség, ha egy objektum a kupacban lefoglalt objektumokra mutat mutatókat . Ha a programozó nem hoz létre másoláskonstruktort, akkor a fordító létrehoz egy implicit másoláskonstruktort, amely a mutatókat úgy másolja, ahogy vannak , azaz nem történik meg az adatok tényleges másolása, és a két objektum ugyanarra az adatra hivatkozik a kupacban. Ennek megfelelően a „másolat” megváltoztatására tett kísérlet megsérti az eredetit, és az egyik objektum destruktorának meghívása a másik későbbi használatával olyan memóriaterülethez vezet, amely már nem tartozik a programhoz.
Az argumentumot hivatkozással kell átadni , nem érték szerint . Ez ütközésből következik: ha egy objektumot érték szerint adunk át (különösen a konstruktor meghívásához), az objektumot másolni kell. De egy objektum másolásához meg kell hívnia a másoláskonstruktort.
Egy konstruktor, amely egy argumentumot vesz fel. Megadja az argumentum típuskonverzióját a konstruktor típusává. Ez a típuskonverzió csak akkor kerül alkalmazásra, ha egyedi.
A felhasználó által definiált típuskonverzió két formát ölthet: - C-típusból bármely T-típusba, amelyhez C-nek rendelkeznie kell egy C::operátorral T() - bármely T-típusból C-típusba, amelyhez C-ben a következőnek kell lennie: C::C(T) (vagy C::C(T&), vagy C::C(T&&))
Ha mindkét eset megengedett egy kifejezésben, akkor kétértelműség és fordítási hiba lép fel.
Ha egy konstruktort (vagy T() operátort) az explicit kulcsszóval jelölünk meg, akkor az ilyen típusú konverziót csak akkor alkalmazzuk, ha létezik (T)C vagy static_cast<T>C formájú explicit öntött művelet. Ha nincs kifejezett szó, akkor a fordító akár implicit módon is beilleszthet egy ilyen konverziót, például az f(T arg) függvény f(C) formában történő meghívásakor.
A C ++11 bevezeti a nem állandó hivatkozások új típusát, az rvalue referenciát és a jelöléssel T&&, valamint egy újfajta konstruktort – a konstruktorok mozgatását . A mozgatási konstruktor bemenetként egy osztályobjektumra mutató nem állandó hivatkozás értékét veszi fel, és az objektum erőforrásainak tulajdonjogát adja át. A Move konstruktorokat az ideiglenes objektumok létrehozásával járó hatékonyságveszteség megoldására találták ki.
A konstruktor nem virtuális a virtuális metódus értelmében – a virtuális metódusok mechanizmusának működéséhez le kell futtatnia a konstruktort, amely automatikusan beállítja az objektum virtuális metódustábláját .
A "virtuális konstruktorok" egy hasonló, de eltérő mechanizmusra utalnak, amely bizonyos nyelveken található, például a Delphiben , de nem a C++- ban és a Java -ban . Ez a mechanizmus lehetővé teszi bármely korábban ismeretlen osztály objektumának létrehozását két feltétel mellett:
Bekerül a nyelvbe az úgynevezett osztálytípus ( metaclass ). Ez a típus felveheti értékként a -ból származó bármely osztály nevét TVehicle.
típus CVehicle = TVjármű osztály ; _Ez a mechanizmus lehetővé teszi bármely korábban ismeretlen osztályból származó objektumok létrehozását TVehicle.
var cv : CJármű ; v : TVjármű ; cv := TAutomobile ; v := cv . létrehozni ;Figyeld meg, hogy a kód
cv := TMoped ; v := cv . létrehozni ;hibás - az irányelv reintroducemegszakította a virtuális metódus felülírásának láncát, és valójában a konstruktort hívják meg TMotorcycle.Create(ami azt jelenti, hogy egy motorkerékpárt hoznak létre, nem egy mopedet!)
Lásd még: Gyári (tervminta)
A konstruktor nevének meg kell egyeznie az osztály nevével. Több azonos nevű, de eltérő paraméterekkel rendelkező konstruktor megengedett .
Példa class ClassWithConstructor { nyilvános : /* A belső objektum inicializálása a konstruktorral */ ClassWithConstructor ( float paraméter ) : objektum ( paraméter ) {} /* konstruktor meghívása AnotherClass(float); */ privát : AnotherClass objektum ; };A Pythonban a konstruktor egy osztálymetódus, melynek neve __init__. Ne feledje továbbá, hogy bármely metódus első argumentumának az osztálykörnyezetre mutató mutatónak kell lennie self.
Példa osztály ClassWithConstructorral : def __init__ ( self ): """Ez a metódus konstruktor.""" passA Ruby nyelv egy speciális módszerrel állítja be az objektumot a kezdeti konzisztens állapotába initialize.
Példa class ClassWithConstructor def inicializálás print 'Ez a metódus konstruktor.' vége végeA Delphiben a C++ -tól eltérően a konstruktor a kulcsszóval van deklarálva constructor. A konstruktor neve bármi lehet, de ajánlatos a konstruktort elnevezni Create.
Példa TClassWithConstructor = osztály nyilvános konstruktor Create ; vége ;Néhány különbség a konstruktorok és más Java metódusok között :
A JavaScriptben a konstruktor egy szabályos függvény, amelyet az operátor operandusaként használnak new. A kulcsszó a létrehozott objektumra utal this.
Az ECMAScript 6 specifikáció azonban hozzáadott egy prototípus szintaktikai wrappert, amely olyan OOP tulajdonságokkal rendelkezik , mint az öröklődés, valamint a szükséges metódusok egy kis listája, például: toString().
Példa function Példa ( initValue ) { this . myValue = initValue ; } példa . prototípus . getMyValue = function () { return this . myValue ; } //ES6 class class Példa { constructor () { console . log ( 'konstruktor' ); } } // kód, amely szemlélteti egy objektum létrehozását a fent leírt konstruktorral var exampleObject = new Példa ( 120 );A Visual Basic .NET konstruktorai egy szabályos deklarációs metódust használnak New.
Példa Class Foobar Private strData As String ' Constructor Public Sub New ( ByVal someParam As String ) strData = someParam End Sub End Class ' néhány kód ', amely egy objektum létrehozását illusztrálja a fenti Dim foo As New Foobar ( ".NET" ) konstruktorralAz Eiffelben az objektumokat inicializáló rutinokat létrehozási eljárásoknak nevezzük . A létrehozási eljárások némileg hasonlóak a konstruktorokhoz, és némileg különböznek. A következő jellemzőkkel rendelkeznek:
Bár az objektum létrehozása bizonyos finomságok tárgyát képezi [3. megjegyzés]x: T , egy attribútum létrehozása létrehozási utasításként kifejezett típusdeklarációval create x.makea következő lépésekből áll:
Az alábbi első rész meghatározza az osztályt POINT. Az eljárás makea kulcsszó után van kódolva feature.
A kulcsszó createbemutatja az osztály példányainak inicializálására használható eljárások listáját. Ebben az esetben a lista tartalmaz default_createegy eljárást, amelynek üres implementációja az osztályból örökölt ANY, és egy olyan eljárást make, amelynek megvalósítása magában az osztályban található POINT.
class POINT létre default_create , make funkció make ( a_x_érték : REAL ; a_y_érték : REAL ) do x := a_x_érték y := a_y_érték vége x : REAL -- X koordináta y : REAL -- Y koordináta ...A második szakaszban az osztály kliensének számító osztálynak vannak típusú POINTdeklarációi . my_point_1my_point_2POINT
A szubrutin kódjában my_point_1a koordinátákkal (0.0; 0.0) jön létre. Mivel a létrehozási utasításban nincs megadva létrehozási eljárás, a rendszer default_createaz osztályból örökölt eljárást használja ANY. Ugyanez a sor átírható így create my_point_1.default_create. Csak a create eljárásként megadott eljárások használhatók a create utasításokban (vagyis a kulcsszóval rendelkező utasításokban create).
Ezután jön a létrehozási utasítás my_point_2, amely beállítja a koordináták kezdeti értékeit my_point_2.
A harmadik utasítás normál eljáráshívást hajt végre a különböző értékekkel makecsatolt példány újrainicializálására .my_point_2
my_point_1 : POINT my_point_2 : POINT ... saját_pont_1 létrehozása Saját_pont_2 létrehozása . make ( 3.0 , 4.0 ) my_point_2 . gyártmány ( 5.0 , 8.0 ) ...Meg kell jegyezni, hogy a ColdFusionban nincs konstruktor módszer . A ColdFusion programozói közösségben elterjedt módszer a " " metódus initpszeudokonstruktorként való meghívása.
<cfcomponent displayname = "Sajt" > <!--- tulajdonságok ---> <cfset változók . cheeseName = "" / > <!--- pszeudokonstruktor ---> <cffunction name = "init" returntype = "Sajt" > <cfargument name = "cheeseName" type = "string" required = "true" / > <cfset változók . cheeseName = argumentumok . cheeseName / > <cfreturn this / > </cffunction> </cfcomponent>A PHP -ben (5-ös verzió óta) a konstruktor egy olyan metódus __construct(), amelyet egy kulcsszó automatikusan meghív newaz objektum létrehozása után. Általában különféle automatikus inicializálások végrehajtására szolgál, például tulajdonság inicializálására. A konstruktorok argumentumokat is vehetnek, ebben az esetben egy kifejezés megadásakor newa formális paramétereket zárójelben kell átadni a konstruktornak.
class Személy { privát $név ; function __construct ( $name ) { $this -> name = $name ; } function getName () { return $this -> name ; } }A PHP 4-es (és korábbi) verziójában azonban egy konstruktor ugyanazzal az osztálynévvel rendelkező osztálymetódus.
class Személy { privát $név ; function Személy ( $név ) { $this -> name = $name ; } function getName () { return $this -> name ; } }Perlben a konstruktornak alkalmaznia kell a bless függvényt valamilyen változóra (általában egy hash hivatkozásra):
csomag Példa ; sub new { my $class = shift ; én $én = {}; return bless $self , $class ; } 1 ;De ez a minimális alap opció, sok fejlettebb módszer létezik, a használati mezőktől a Moose-ig.
A konstruktorok mindig részei az osztályok megvalósításának. Az osztály (a programozásban) az osztályba tartozó objektumok halmazának alapvető jellemzőinek specifikációit írja le, nem pedig bármelyik objektum egyedi jellemzőit. Nézzünk egy egyszerű analógiát. Vegyünk példának egy adott iskola tanulóinak halmazát (vagy osztályát, hogy általánosabb jelentését használjuk). Így rendelkezünk:
osztályos tanuló { // a tanulói osztály leírása // ... másik kód ... }Az óra azonban Student csak egy általános sablon (prototípus) diákjaink számára. Használatához a programozó minden tanulót objektumként vagy entitásként ( implementációként ) hoz létre az osztályban. Ez az objektum az a valós adat a memóriában, amelynek méretét, mintáját, jellemzőit és (bizonyos mértékben) viselkedését az osztálydefiníció határozza meg. Az objektumok létrehozásának szokásos módja egy konstruktor meghívása (az osztályoknak általában lehetnek külön konstruktorai). Például,
osztályos tanuló { Tanuló(karakterlánc diáknév, karakterlánc-cím, int azonosító) { // ... itt tároljuk a bemeneti adatokat és egyéb belső mezőket ... } // ... }