I objektorienterad programmering är en klasskonstruktor (från engelska constructor ) ett speciellt block med instruktioner som kallas när ett objekt skapas.
En av nyckelfunktionerna i OOP är inkapsling : de interna fälten i klassen är inte direkt tillgängliga, och användaren kan bara arbeta med objektet som helhet, genom offentliga ( public) metoder. Varje metod bör helst utformas så att ett objekt som är i ett "giltigt" tillstånd (det vill säga när klassen invariant uppfylls ) också är i ett giltigt tillstånd när metoden anropas. Och den första uppgiften för konstruktören är att överföra objektets fält till ett sådant tillstånd.
Den andra uppgiften är att förenkla användningen av objektet. Ett objekt är inte en " sak i sig ", det måste ofta kräva viss information från andra objekt: till exempel Filemåste ett objekt, när det skapas, få ett filnamn. Detta kan också göras via metoden:
fil fil ; fil . open ( "in.txt" , File :: omRead );Men det är bekvämare att öppna filen i konstruktorn: [1]
Filfil ( "in.txt" , Fil :: omRead ) ;En mängd olika programmeringsspråk presenterar flera varianter av konstruktörer:
Konstruktörer som tar ett eller flera argument kallas parametriserade. Till exempel:
klassexempel _ { int x , y ; offentliga : exempel (); Exempel ( int a , int b ); // parameteriserad konstruktor }; Exempel :: Exempel () { } Exempel :: Exempel ( int a , int b ) { x = a ; y = b ; }En parameteriserad konstruktor kan anropas explicit eller implicit, till exempel:
Exempel e = Exempel ( 0 , 50 ); // explicit samtal Exempel e ( 0 , 50 ); // implicit samtalEn konstruktor utan nödvändiga argument. Används när du skapar arrayer av objekt, anropade för att skapa varje instans. I avsaknad av en explicit standardkonstruktor genereras dess kod av kompilatorn (vilket naturligtvis inte återspeglas i källtexten).
En konstruktor vars argument är en referens till ett objekt av samma klass. Används i C++ för att skicka objekt till funktioner efter värde .
Kopieringskonstruktorn behövs oftast när ett objekt har pekare till objekt som är allokerade på högen . Om programmeraren inte skapar en kopieringskonstruktor, kommer kompilatorn att skapa en implicit kopieringskonstruktor som kopierar pekarna som de är , dvs. ingen faktisk kopiering av data sker och de två objekten refererar till samma data på högen. Följaktligen kommer ett försök att ändra "kopian" att skada originalet, och att anropa förstöraren för ett av dessa objekt, med efterföljande användning av det andra, kommer att leda till åtkomst till ett minnesområde som inte längre tillhör programmet.
Argumentet måste skickas genom referens , inte genom värde . Detta följer av en kollision: när man skickar ett objekt efter värde (särskilt för att anropa en konstruktor), krävs att objektet kopieras. Men för att kopiera ett objekt måste du anropa kopieringskonstruktorn.
En konstruktör som tar ett argument. Anger typkonverteringen av dess argument till typen av konstruktor. Denna typkonvertering tillämpas endast implicit om den är unik.
En användardefinierad typkonvertering kan ha en av två former: - från en klass typ C till vilken typ som helst T, för vilken C måste ha en C::operator T() - från vilken typ T som helst till en klass typ C, för vilken C måste ha C::C(T) (eller C::C(T&), eller C::C(T&&))
Om båda dessa fall tillåts i ett uttryck uppstår en tvetydighet och ett kompileringsfel.
Om en konstruktor (eller operator T()) är markerad med det explicita nyckelordet, tillämpas en sådan typkonvertering endast om det finns en explicit cast-operation av formen (T)C eller static_cast<T>C. Om det inte finns något explicit ord kan kompilatorn infoga en sådan konvertering även implicit, till exempel när funktionen f(T arg) anropas i formen f(C).
C ++11 introducerar en ny typ av icke-konstanta referenser som kallas rvalue- referens och betecknas som T&&, och en ny typ av konstruktorer — flytta konstruktörer . Flyttkonstruktorn tar som indata värdet av en icke-konstant referens till ett klassobjekt och används för att överföra äganderätten till det objektets resurser. Flyttkonstruktörer uppfanns för att lösa effektivitetsförlusten i samband med att skapa tillfälliga objekt.
En konstruktor är inte virtuell i betydelsen en virtuell metod - för att den virtuella metodmekanismen ska fungera måste du köra konstruktorn, som automatiskt ställer in den virtuella metodtabellen för detta objekt.
"Virtuella konstruktörer" hänvisar till en liknande men annorlunda mekanism som finns i vissa språk, som Delphi men inte C++ och Java . Denna mekanism låter dig skapa ett objekt av vilken som helst tidigare okänd klass under två villkor:
Den så kallade klasstypen ( metaclass ) introduceras i språket. Den här typen kan ta namnet på vilken klass som helst som härrör från TVehicle.
typ CVehicle = klass av TV- fordon ;Denna mekanism låter dig skapa objekt av vilken som helst tidigare okänd klass som härrör från TVehicle.
var cv : CVehicle ; v : TV-fordon ; cv := TAutomobile ; v := cv . skapa ;Lägg märke till att koden
cv := TMoped ; v := cv . skapa ;är felaktigt - direktivet har reintroducebrutit kedjan för att åsidosätta den virtuella metoden, och i själva verket kommer konstruktören att kallas TMotorcycle.Create(vilket betyder att en motorcykel kommer att skapas, inte en moped!)
Se även Factory (designmönster)
Namnet på konstruktören måste matcha klassens namn. Flera konstruktörer med samma namn men olika parametrar är tillåtna .
Exempel klass ClassWithConstructor { offentliga : /* Initiera internt objekt med konstruktorn */ ClassWithConstructor ( float - parameter ) : objekt ( parameter ) {} /* anropa konstruktorn AnotherClass(float); */ privat : AnotherClass objekt ; };I Python är en konstruktor en klassmetod som heter __init__. Glöm inte heller att det första argumentet till någon metod måste vara en pekare till klasskontexten self.
Exempel klass ClassWithConstructor : def __init__ ( self ): """Denna metod är konstruktor.""" passRuby - språket använder en speciell metod för att ställa in ett objekt till dess ursprungliga konsekventa tillstånd initialize.
Exempel class ClassWithConstructor def initialize print 'Denna metod är konstruktor.' slutändan _I Delphi , till skillnad från C++ , deklareras konstruktorn med nyckelordet constructor. Namnet på konstruktören kan vara vad som helst, men det rekommenderas att namnge konstruktorn Create.
Exempel TClassWithConstructor = klass offentlig konstruktor Skapa ; slut ;Några skillnader mellan konstruktörer och andra Java -metoder :
I JavaScript är konstruktorn en vanlig funktion som används som operand för operatorn new. Nyckelordet används för att referera till det skapade objektet this.
Men ECMAScript 6-specifikationen lade till en prototypsyntaktisk omslag, som har sådana OOP- egenskaper som arv, såväl som en liten lista över nödvändiga metoder, till exempel: toString().
Exempel function Exempel ( initValue ) { detta . myValue = initValue ; } exempel . prototyp . getMyValue = function () { returnera detta . mitt värde ; } //ES6 klassklass Exempel { constructor ( ) { console . log ( 'konstruktör' ); } } // kod som illustrerar skapandet av ett objekt av konstruktören som beskrivs ovan var exampleObject = new Exempel ( 120 );Konstruktörer i Visual Basic .NET använder en vanlig deklarationsmetod som heter New.
Exempel Klass Foobar Privat strData som sträng ' Constructor Public Sub New ( ByVal someParam As String ) strData = someParam End Sub End Class "någon kod " som illustrerar skapandet av ett objekt av Dim foo As New Foobar ( ".NET" ) - konstruktorn ovanI Eiffel kallas rutiner som initierar objekt skapande procedurer . Skapande procedurer är något liknande konstruktörer och något annorlunda. De har följande egenskaper:
Även om objektskapande är föremål för vissa subtiliteter [Not 3] , så består skapande av ett attribut med en typdeklaration x: Tuttryckt som en skapelsesats create x.makeav följande sekvens av steg:
Det första avsnittet nedan definierar klassen POINT. Proceduren makeär kodad efter nyckelordet feature.
Nyckelordet createintroducerar en lista med procedurer som kan användas för att initiera instanser av klassen. I det här fallet innehåller listan default_create, en procedur med en tom implementering som ärvts från klassen ANYoch en procedur makemed en implementering i själva klassen POINT.
klass POINT skapa default_create , make funktion make ( a_x_value : REAL ; a_y_value : REAL ) do x := a_x_value y := a_y_value end x : REAL -- X-koordinat y : VERKLIG -- Y koordinat ...I det andra avsnittet har klassen som är klienten till klassen POINTdeklarationer my_point_1av my_point_2typen POINT.
I subrutinkoden my_point_1skapas den med koordinater (0.0; 0.0). Eftersom ingen skapande procedur anges i skapandesatsen, används proceduren som default_createärvts från klassen ANY. Samma rad skulle kunna skrivas om som create my_point_1.default_create. Endast procedurer som anges som skapa-procedurer kan användas i skapa-satser (det vill säga satser med nyckelordet create).
Därefter kommer skapa-instruktionen för my_point_2, som ställer in de initiala värdena för koordinaterna my_point_2.
Den tredje instruktionen gör ett normalt proceduranrop för makeatt återinitiera den instans som är kopplad till my_point_2med olika värden.
my_point_1 : POINT my_point_2 : POINT ... skapa min_punkt_1 skapa min_punkt_2 . make ( 3.0 , 4.0 ) my_point_2 . make ( 5.0 , 8.0 ) ...Det bör noteras att det inte finns någon konstruktormetod i ColdFusion . En vanlig metod bland ColdFusions programmeringsgemenskap är att kalla metoden ' ' initsom en pseudokonstruktor.
<cfcomponent displayname = "Ost" > <!--- egenskaper ---> <cfset variabler . cheeseName = "" / > <!--- pseudo-constructor ---> <cffunction name = "init" returntype = "Cheese" > <cfargument name = "cheeseName" type = "string" required = "true" / > <cfset variabler . cheeseName = argument . cheeseName / > <cfreturn this / > </cffunction> </cfcomponent>I PHP (sedan version 5) är en konstruktor en metod __construct()som automatiskt anropas av ett nyckelord newefter att ett objekt har skapats. Används vanligtvis för att utföra olika automatiska initieringar, såsom egenskapsinitiering. Konstruktörer kan också ta argument, i vilket fall, när ett uttryck anges newmåste formella parametrar skickas till konstruktorn inom parentes.
klass Person { privat $namn ; funktion __construct ( $name ) { $this -> name = $name ; } function getName () { return $this -> name ; } }En konstruktor i PHP version 4 (och tidigare) är dock en klassmetod med samma klassnamn.
klass Person { privat $namn ; function Person ( $name ) { $this -> name = $name ; } function getName () { return $this -> name ; } }I Perl måste konstruktorn tillämpa välsignelsefunktionen på någon variabel (vanligtvis en hashreferens):
paket Exempel ; sub new { min $klass = skift ; mitt $jag = {}; återvända välsigna $själv , $klass ; } 1 ;Men detta är det minsta grundläggande alternativet, det finns många mer avancerade metoder, allt från användningsfält till älg.
Konstruktörer är alltid en del av genomförandet av klasser. En klass (i programmering) beskriver specifikationerna för de grundläggande egenskaperna för den uppsättning objekt som är medlemmar i klassen, inte de individuella egenskaperna för något av objekten. Låt oss titta på en enkel analogi. Ta som exempel en uppsättning (eller klass, för att använda dess mer allmänna betydelse) av elever från en viss skola. Så vi har:
klass elev { // beskrivning av elevklassen // ... annan kod ... }Klassen Student är dock bara en generell mall (prototyp) för våra elever. För att använda det skapar programmeraren varje elev som ett objekt eller entitet ( implementering ) av klassen. Detta objekt är den verkliga biten av data i minnet vars storlek, mönster, egenskaper och (till viss del) beteende definieras av klassdefinitionen. Det vanliga sättet att skapa objekt är att anropa en konstruktor (klasser kan i allmänhet ha separata konstruktorer). Till exempel,
klass elev { Student(String studentName, String Address, int ID) { // ... här lagrar vi indata och andra interna fält ... } // ... }