I objektorienteret programmering er en klassekonstruktør (fra den engelske constructor ) en speciel blok af instruktioner kaldet når et objekt oprettes.
En af nøglefunktionerne ved OOP er indkapsling : Klassens interne felter er ikke direkte tilgængelige, og brugeren kan kun arbejde med objektet som helhed gennem offentlige ( public) metoder. Hver metode bør ideelt set designes således, at et objekt, der er i en "gyldig" tilstand (det vil sige, når klassen invariant er opfyldt ) også er i en gyldig tilstand, når metoden påkaldes. Og konstruktørens første opgave er at overføre objektets felter til en sådan tilstand.
Den anden opgave er at forenkle brugen af objektet. Et objekt er ikke en " ting i sig selv ", det skal ofte kræve noget information fra andre objekter: for eksempel skal et objekt File, når det oprettes, modtage et filnavn. Dette kan også gøres via metoden:
fil fil ; fil . open ( "in.txt" , Fil :: omRead );Men det er mere praktisk at åbne filen i konstruktøren: [1]
Fil fil ( "in.txt" , Fil :: omRead );En række programmeringssprog præsenterer flere varianter af konstruktører:
Konstruktører, der tager et eller flere argumenter, kaldes parametriserede. For eksempel:
klasse eksempel { int x , y ; offentligt : eksempel (); Eksempel ( int a , int b ); // parameteriseret konstruktør }; Eksempel :: Eksempel () { } Eksempel :: Eksempel ( int a , int b ) { x = a ; y = b ; }En parameteriseret konstruktør kan kaldes eksplicit eller implicit, for eksempel:
Eksempel e = Eksempel ( 0 , 50 ); // eksplicit opkald Eksempel e ( 0 , 50 ); // implicit opkaldEn konstruktør uden påkrævede argumenter. Bruges ved oprettelse af arrays af objekter, kaldet til at oprette hver instans. I mangel af en eksplicit standardkonstruktør genereres dens kode af compileren (hvilket selvfølgelig ikke afspejles i kildeteksten).
En konstruktør, hvis argument er en reference til et objekt af samme klasse. Bruges i C++ til at sende objekter til funktioner efter værdi .
Kopikonstruktøren er for det meste nødvendig, når et objekt har pointere til objekter, der er allokeret på heapen . Hvis programmøren ikke opretter en kopikonstruktør, vil compileren oprette en implicit kopikonstruktør, der kopierer pointerne som de er , dvs. der sker ingen egentlig kopiering af dataene, og de to objekter refererer til de samme data på heapen. Følgelig vil et forsøg på at ændre "kopien" beskadige originalen, og at kalde destruktoren for et af disse objekter, med efterfølgende brug af det andet, vil føre til adgang til et hukommelsesområde, der ikke længere hører til programmet.
Argumentet skal sendes ved reference , ikke efter værdi . Dette følger af en kollision: når du sender et objekt efter værdi (især for at kalde en konstruktør), er det nødvendigt at kopiere objektet. Men for at kopiere et objekt skal du kalde kopikonstruktøren.
En konstruktør, der tager ét argument. Specificerer typekonverteringen af dets argument til typen af konstruktøren. Denne typekonvertering anvendes kun implicit, hvis den er unik.
En brugerdefineret typekonvertering kan have en af to former: - fra en klassetype C til en hvilken som helst type T, for hvilken C skal have en C::operator T() - fra en hvilken som helst type T til en klassetype C, for hvilken C skal have C::C(T) (eller C::C(T&), eller C::C(T&&))
Hvis begge disse tilfælde tillades i et udtryk, opstår der en flertydighed og en kompileringsfejl.
Hvis en konstruktør (eller operator T()) er markeret med det eksplicitte nøgleord, anvendes en sådan typekonvertering kun, hvis der er en eksplicit cast-operation af formen (T)C eller static_cast<T>C. Hvis der ikke er noget eksplicit ord, så kan compileren indsætte en sådan konvertering selv implicit, for eksempel når funktionen f(T arg) kaldes i formen f(C).
C ++11 introducerer en ny type ikke-konstante referencer kaldet rvalue reference og betegnet som T&&, og en ny slags konstruktør - flyt konstruktører . Flyttekonstruktøren tager værdien af en ikke-konstant reference til et klasseobjekt som input og bruges til at overføre ejerskab af det objekts ressourcer. Move-konstruktører blev opfundet for at løse effektivitetstabet forbundet med at skabe midlertidige objekter.
En konstruktør er ikke virtuel i betydningen en virtuel metode - for at den virtuelle metode-mekanisme skal fungere, skal du køre konstruktøren, som automatisk opsætter den virtuelle metodetabel for dette objekt.
"Virtuelle konstruktører" refererer til en lignende, men anderledes mekanisme, der findes i nogle sprog, såsom Delphi , men ikke C++ og Java . Denne mekanisme giver dig mulighed for at oprette et objekt af enhver tidligere ukendt klasse under to betingelser:
Den såkaldte klassetype ( metaklasse ) introduceres i sproget. Denne type kan tage navnet på enhver klasse afledt af som værdi TVehicle.
type CVehicle = klasse af TVehicle ;Denne mekanisme giver dig mulighed for at oprette objekter af enhver tidligere ukendt klasse afledt af TVehicle.
var cv : CVehicle ; v : TV-køretøj ; cv := TAutomobil ; v := cv . skabe ;Bemærk, at koden
cv := TMoped ; v := cv . skabe ;er forkert - direktivet har reintroducebrudt kæden med at tilsidesætte den virtuelle metode, og faktisk vil konstruktøren blive kaldt TMotorcycle.Create(hvilket betyder, at der bliver skabt en motorcykel, ikke en knallert!)
Se også Fabrik (designmønster)
Navnet på konstruktøren skal svare til navnet på klassen. Flere konstruktører med samme navn, men forskellige parametre er tilladt .
Eksempel klasse ClassWithConstructor { offentligt : /* Initialiser internt objekt med konstruktør */ ClassWithConstructor ( float parameter ) : objekt ( parameter ) {} /* kalder constructor AnotherClass(float); */ privat : AnotherClass objekt ; };I Python er en konstruktør en klassemetode ved navn __init__. Glem heller ikke, at det første argument til enhver metode skal være en pegepind til klassens kontekst self.
Eksempel klasse ClassWithConstructor : def __init__ ( self ): """Denne metode er konstruktør.""" passRuby - sproget bruger en speciel metode til at sætte et objekt til dets oprindelige konsistente tilstand initialize.
Eksempel klasse ClassWithConstructor def initialize print 'Denne metode er konstruktør.' ende endeI Delphi , i modsætning til C++ , er konstruktøren erklæret med nøgleordet constructor. Navnet på konstruktøren kan være hvad som helst, men det anbefales at navngive konstruktøren Create.
Eksempel TClassWithConstructor = klasse offentlig konstruktør Opret ; ende ;Nogle forskelle mellem konstruktører og andre Java- metoder :
I JavaScript er konstruktøren en almindelig funktion, der bruges som operand for operatoren new. Nøgleordet bruges til at henvise til det oprettede objekt this.
Imidlertid tilføjede ECMAScript 6-specifikationen en prototype syntaktisk wrapper, som har sådanne OOP- egenskaber som arv, samt en lille liste over nødvendige metoder, for eksempel: toString().
Eksempel funktion Eksempel ( initValue ) { this . minVærdi = begyndelsesVærdi ; } eksempel . prototype . getMyValue = funktion () { returner dette . minVærdi ; } //ES6 klasse klasse Eksempel { constructor () { console . log ( 'konstruktør' ); } } // kode, der illustrerer oprettelsen af et objekt af konstruktøren beskrevet ovenfor var exampleObject = new Eksempel ( 120 );Konstruktører i Visual Basic .NET bruger en almindelig deklarationsmetode ved navn New.
Eksempel Klasse Foobar Private strData Som streng ' Constructor Public Sub New ( ByVal someParam As String ) strData = someParam End Sub End Class 'noget kode ', der illustrerer oprettelsen af et objekt af Dim foo As New Foobar ( ".NET" ) konstruktøren ovenforI Eiffel kaldes rutiner, der initialiserer objekter, oprettelsesprocedurer . Oprettelsesprocedurer ligner en del konstruktører og noget anderledes. De har følgende egenskaber:
Selvom oprettelse af objekter er genstand for nogle finesser [Note 3] , består oprettelse af en attribut med en typeerklæring x: Tudtrykt som en oprettelseserklæring create x.makeaf følgende sekvens af trin:
Den første passage nedenfor definerer klassen POINT. Proceduren makeer kodet efter nøgleordet feature.
Nøgleordet createintroducerer en liste over procedurer, der kan bruges til at initialisere forekomster af klassen. I dette tilfælde indeholder listen default_create, en procedure med en tom implementering, der er arvet fra klassen ANY, og en procedure makemed en implementering i selve klassen POINT.
klasse POINT oprette 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 : RIGTIG -- Y koordinat ...I den anden passage har klassen, der er klienten til klassen POINT, erklæringer my_point_1af my_point_2typen POINT.
I subrutinekoden my_point_1oprettes den med koordinater (0.0; 0.0). Da der ikke er angivet nogen oprettelsesprocedure i oprettelsessætningen, bruges proceduren, der er default_createarvet fra klassen ANY. Den samme linje kunne omskrives som create my_point_1.default_create. Kun procedurer, der er angivet som oprette-procedurer, kan bruges i oprette-sætninger (det vil sige sætninger med nøgleordet create).
Dernæst kommer opret-instruktionen for my_point_2, som sætter startværdierne for koordinaterne my_point_2.
Den tredje instruktion foretager et normalt procedurekald for makeat geninitialisere den instans, der er knyttet til, my_point_2med forskellige værdier.
mit_punkt_1 : PUNKT mit_punkt_2 : PUNKT ... opret mit_punkt_1 opret mit_punkt_2 . make ( 3.0 , 4.0 ) mit_punkt_2 . make ( 5.0 , 8.0 ) ...Det skal bemærkes, at der ikke er nogen konstruktørmetode i ColdFusion . En almindelig metode blandt ColdFusion-programmeringsfællesskabet er at kalde ' '-metoden initsom en pseudo-konstruktør.
<cfcomponent displayname = "Ost" > <!--- egenskaber ---> <cfset variabler . cheeseName = "" / > <!--- pseudo-constructor ---> <cffunction name = "init" returntype = "Cheese" > <cfargument name = "cheeseName" type = "string" required = "true" / > <cfset variabler . cheeseName = argumenter . cheeseName / > <cfreturn this / > </cffunction> </cfcomponent>I PHP (siden version 5) er en konstruktør en metode __construct(), der automatisk kaldes af et nøgleord, newefter at et objekt er blevet oprettet. Anvendes typisk til at udføre forskellige automatiske initialiseringer, såsom egenskabsinitialisering. Konstruktører kan også tage argumenter, i hvilket tilfælde, når et udtryk er angivet new, skal formelle parametre sendes til konstruktøren i parentes.
klasse Person { privat $navn ; funktion __construct ( $navn ) { $this -> navn = $navn ; } function getName () { return $this -> name ; } }En konstruktør i PHP version 4 (og tidligere) er dog en klassemetode med samme klassenavn.
klasse Person { privat $navn ; function Person ( $navn ) { $this -> navn = $navn ; } function getName () { return $this -> name ; } }I Perl skal konstruktøren anvende velsignefunktionen på en eller anden variabel (normalt en hash-reference):
pakke Eksempel ; sub new { min $klasse = skift ; mit $selv = {}; retur velsigne $selv , $klasse ; } 1 ;Men dette er den mindste grundlæggende mulighed, der er mange mere avancerede metoder, lige fra brugsfelter til Moose.
Konstruktører er altid en del af implementeringen af klasser. En klasse (i programmering) beskriver specifikationerne for de grundlæggende egenskaber for det sæt af objekter, der er medlemmer af klassen, ikke de individuelle karakteristika for nogen af objekterne. Lad os se på en simpel analogi. Tag som eksempel et sæt (eller klasse, for at bruge dets mere generelle betydning) af elever fra en bestemt skole. Vi har således:
klasse elev { // beskrivelse af elevklassen // ... anden kode ... }Klassen Student er dog blot en generel skabelon (prototype) for vores elever. For at bruge det opretter programmøren hver elev som et objekt eller en enhed ( implementering ) af klassen. Dette objekt er det rigtige stykke data i hukommelsen, hvis størrelse, mønster, karakteristika og (til en vis grad) adfærd er defineret af klassedefinitionen. Den sædvanlige måde at oprette objekter på er at kalde en konstruktør (klasser kan generelt have separate konstruktører). For eksempel,
klasse elev { Student(String studentName, String Address, int ID) { // ... her gemmer vi inputdata og andre interne felter ... } //... }