Konstruktor (objektorientierte Programmierung) - Constructor (object-oriented programming)

In der klassenbasierten objektorientierten Programmierung ist ein Konstruktor (Abkürzung: ctor ) eine spezielle Art von Unterprogramm, die aufgerufen wird, um ein Objekt zu erstellen . Es bereitet das neue Objekt für die Verwendung vor und akzeptiert oft Argumente , die der Konstruktor verwendet, um erforderliche Membervariablen zu setzen .

Ein Konstruktor ähnelt einer Instanzmethode , unterscheidet sich jedoch von einer Methode dadurch, dass er keinen expliziten Rückgabetyp hat , nicht implizit vererbt wird und normalerweise andere Regeln für Bereichsmodifikatoren hat. Konstruktoren haben oft denselben Namen wie die deklarierende Klasse . Sie haben die Aufgabe, die Datenelemente des Objekts zu initialisieren und die Invariante der Klasse festzulegen , die bei ungültiger Invariante fehlschlägt. Ein richtig geschriebener Konstruktor hinterlässt das resultierende Objekt in einem gültigen Zustand. Unveränderliche Objekte müssen in einem Konstruktor initialisiert werden.

Die meisten Sprachen erlauben das Überladen des Konstruktors, da es mehr als einen Konstruktor für eine Klasse mit unterschiedlichen Parametern geben kann. Einige Sprachen berücksichtigen einige spezielle Typen von Konstruktoren. Konstruktoren, die konkret eine einzelne Klasse verwenden, um Objekte zu erstellen und eine neue Instanz der Klasse zurückzugeben, werden von Factories abstrahiert , die ebenfalls Objekte erstellen, dies jedoch auf verschiedene Weise tun können, indem sie mehrere Klassen oder verschiedene Zuordnungsschemata wie einen Objektpool verwenden .

Typen

Parametrisierte Konstruktoren

Konstruktoren, die mindestens ein Argument annehmen können, werden als parametrisierte Konstruktoren bezeichnet. Wenn ein Objekt in einem parametrisierten Konstruktor deklariert wird, müssen die Anfangswerte als Argumente an die Konstruktorfunktion übergeben werden. Die normale Art der Objektdeklaration funktioniert möglicherweise nicht. Die Konstruktoren können explizit oder implizit aufgerufen werden. Die Methode zum impliziten Aufruf des Konstruktors wird auch als Kurzschriftmethode bezeichnet. Wenn wir Felder der Klasse mit Ihren eigenen Werten initialisieren möchten, verwenden Sie einen parametrisierten Konstruktor.

class Example {
 public:
  Example();
  Example(int a, int b);  // Parameterized constructor.

 private:
  int x_;
  int y_;
};

Example::Example() = default;

Example::Example(int x, int y) : x_(x), y_(y) {}
Example e = Example(0, 50);  // Explicit call.
Example e2(0, 50);  // Implicit call.

Standardkonstruktoren

Wenn der Programmierer keinen Konstruktor für eine instanziierbare Klasse bereitstellt, fügt der Java-Compiler in Ihrem Namen einen Standardkonstruktor in Ihren Code ein. Dieser Konstruktor wird als Standardkonstruktor bezeichnet. Sie würden es in Ihrem Quellcode (der Java-Datei) nicht finden, da es während der Kompilierung in den Code eingefügt würde und in der .class-Datei vorhanden ist. Das Verhalten des Standardkonstruktors ist sprachabhängig. Es kann Datenelemente auf Null oder andere gleiche Werte initialisieren, oder es kann überhaupt nichts tun. In Java bezieht sich ein "Standardkonstruktor" auf einen nullären Konstruktor, der automatisch vom Compiler generiert wird, wenn keine Konstruktoren für die Klasse definiert wurden oder keine vom Programmierer definierten Konstruktoren vorhanden sind (z. B. in Java ruft der Standardkonstruktor implizit die Nullary-Konstruktor der Superklasse und führt dann einen leeren Rumpf aus). Alle Felder werden auf ihrem Anfangswert 0 (Ganzzahltypen), 0.0 (Gleitkommatypen), false (boolescher Typ) oder null (Referenztypen) belassen.

#include <iostream>

class Student {
 public:
  Student(int a = 0, int b = 0);  // Default constructor.

  int a;
  int b;
};

Konstruktoren kopieren

Wie C++ unterstützt auch Java "Copy Constructor". Aber im Gegensatz zu C++ erstellt Java keinen Standardkopiekonstruktor, wenn Sie keinen eigenen schreiben. Kopierkonstruktoren definieren die Aktionen, die der Compiler beim Kopieren von Klassenobjekten ausführt. Ein Copy-Konstruktor hat einen formalen Parameter, der dem Typ der Klasse entspricht (der Parameter kann eine Referenz auf ein Objekt sein). Es wird verwendet, um eine Kopie eines vorhandenen Objekts derselben Klasse zu erstellen. Obwohl beide Klassen gleich sind, zählt sie als Konvertierungskonstruktor. Während Kopierkonstruktoren normalerweise mit copy ctor oder cctor abgekürzt werden, haben sie nichts mit Klassenkonstruktoren zu tun, die in .NET mit derselben Abkürzung verwendet werden.

Konvertierungskonstruktoren

Konvertierungskonstruktoren bieten einem Compiler die Möglichkeit, implizit ein Objekt einer Klasse basierend auf einem Objekt eines anderen Typs zu erstellen. Diese Konstruktoren werden normalerweise implizit aufgerufen, um Argumente oder Operanden in einen geeigneten Typ zu konvertieren, sie können jedoch auch explizit aufgerufen werden.

Konstrukteure verschieben

In C++ nehmen Bewegungskonstruktoren eine Wertreferenz auf ein Objekt der Klasse und werden verwendet, um die Eigentumsübertragung der Ressourcen des Parameterobjekts zu implementieren.

Syntax

  • Java , C++ , C# , ActionScript , PHP 4 und MATLAB haben eine Namenskonvention, in der Konstruktoren denselben Namen haben wie die Klasse, mit der sie verknüpft sind.
  • In PHP 5 ist ein empfohlener Name für einen Konstruktor __construct. Aus Gründen der Abwärtskompatibilität wird eine Methode mit demselben Namen wie die Klasse aufgerufen, wenn die __constructMethode nicht gefunden werden kann. Seit PHP 5.3.3 funktioniert dies nur für Klassen ohne Namespace.
  • In PHP 7 sollten Sie den Konstruktor immer als __construct. Methoden mit demselben Namen wie die Klasse lösen einen Fehler der Ebene E_DEPRECATED aus.
  • In Perl werden Konstruktoren per Konvention als "neu" bezeichnet und müssen eine Menge Objekte erstellen.
  • Im Moose-Objektsystem für Perl werden Konstruktoren (namens new ) automatisch erstellt und durch die Angabe einer BUILD- Methode erweitert.
  • In Visual Basic .NET heißt der Konstruktor " New".
  • In Python ist der Konstruktor auf zwei Methoden aufgeteilt, " __new__" und " __init__". Die __new__Methode ist für die Zuweisung von Speicher für die Instanz verantwortlich und empfängt die Klasse als Argument (herkömmlich " cls" genannt). Der __init__Methode (oft "der Initialisierer" genannt) wird die neu erstellte Instanz als Argument übergeben (herkömmlich " self" genannt).
  • Object Pascal- Konstruktoren werden durch das Schlüsselwort " constructor" gekennzeichnet und können benutzerdefinierte Namen haben (meistens werden sie jedoch " Create" genannt).
  • In Objective-C ist die Konstruktormethode auf zwei Methoden aufgeteilt, " alloc" und " init", wobei die allocMethode Speicher für eine Instanz der Klasse reserviert (zuordnet) und die initMethode den Großteil der Initialisierung der Instanz übernimmt. Ein Aufruf der Methode " new" ruft sowohl die allocals auch die initMethoden für die Klasseninstanz auf.

Speicherorganisation

In Java, C# und VB .NET erstellt der Konstruktor Referenztypobjekte in einer speziellen Speicherstruktur, die als " Heap " bezeichnet wird. Werttypen (wie int, double usw.) werden in einer sequentiellen Struktur namens " Stack " erstellt. VB .NET und C# ermöglichen auch die Verwendung des new- Operators zum Erstellen von Werttypobjekten, aber diese Werttypobjekte werden auf dem Stack erstellt, unabhängig davon, ob der Operator verwendet wird oder nicht.

In C++ werden Objekte auf dem Stack erstellt, wenn der Konstruktor ohne den new-Operator aufgerufen wird, und auf dem Heap, wenn der Konstruktor mit dem new-Operator aufgerufen wird. Stack-Objekte werden implizit gelöscht, wenn sie den Gültigkeitsbereich verlassen, während Heap-Objekte implizit von einem Destruktor oder explizit mit dem Löschoperator gelöscht werden müssen.

Sprachdetails

C++

In C++ ist der Name des Konstruktors der Name der Klasse. Es gibt nichts zurück. Sie kann Parameter wie jede Memberfunktion haben . Konstruktorfunktionen werden normalerweise im öffentlichen Abschnitt deklariert, können aber auch in den geschützten und privaten Abschnitten deklariert werden, wenn der Benutzer den Zugriff darauf einschränken möchte.

Der Konstruktor besteht aus zwei Teilen. Die erste ist die Initialisiererliste, die der Parameterliste folgt und vor dem Methodenrumpf. Es beginnt mit einem Doppelpunkt und die Einträge werden durch Kommas getrennt. Die Initialisierungsliste ist nicht erforderlich, bietet aber die Möglichkeit, Werte für Datenelemente bereitzustellen und separate Zuweisungsanweisungen zu vermeiden. Die Initialisierungsliste ist erforderlich, wenn Sie über Datenmember vom Typ const oder Verweis verfügen oder über Member ohne parameterlose Konstruktorlogik verfügen. Zuweisungen erfolgen gemäß der Reihenfolge, in der Datenmember deklariert werden (auch wenn die Reihenfolge in der Initialisiererliste unterschiedlich ist). Der zweite Teil ist der Rumpf, der ein normaler Methodenrumpf ist, der in geschweifte Klammern eingeschlossen ist.

C++ erlaubt mehr als einen Konstruktor. Die anderen Konstruktoren müssen andere Parameter haben. Außerdem müssen Konstruktoren, die Parameter enthalten, denen Standardwerte zugewiesen werden, die Einschränkung beachten, dass nicht alle Parameter einen Standardwert erhalten. Dies ist eine Situation, die nur dann von Bedeutung ist, wenn ein Standardkonstruktor vorhanden ist. Der Konstruktor einer Basisklasse (oder Basisklassen) kann auch von einer abgeleiteten Klasse aufgerufen werden. Konstruktorfunktionen werden nicht vererbt und auf ihre Adressen kann nicht verwiesen werden. Wenn eine Speicherzuweisung erforderlich ist, werden die Operatoren new und delete implizit aufgerufen.

An einen Kopierkonstruktor wird ein Parameter desselben Typs als const- Referenz übergeben, zum Beispiel Vector(const Vector& rhs) . Wenn es nicht explizit angegeben wird, verwendet der Compiler den Kopierkonstruktor für jede Membervariable oder kopiert einfach Werte bei primitiven Typen. Die Standardimplementierung ist nicht effizient, wenn die Klasse dynamisch zugewiesene Member (oder Handles für andere Ressourcen) hat, da dies bei der Zerstörung zu doppelten Aufrufen zum Löschen (oder doppelten Freigeben von Ressourcen) führen kann.

class Foobar {
 public:
  Foobar(double r = 1.0,
         double alpha = 0.0)  // Constructor, parameters with default values.
      : x_(r * cos(alpha))    // <- Initializer list
  {
    y_ = r * sin(alpha);  // <- Normal assignment
  }

 private:
  double x_;
  double y_;
};

Beispielaufrufe:

Foobar a,
       b(3),
       c(5, M_PI/4);

Beim Zurückgeben von Objekten von Funktionen oder beim Übergeben von Objekten nach Wert wird der Objektkopiekonstruktor implizit aufgerufen, es sei denn, die Rückgabewertoptimierung wird angewendet .

C++ generiert implizit einen Standardkopierkonstruktor, der die Kopiekonstruktoren für alle Basisklassen und alle Membervariablen aufruft, es sei denn, der Programmierer stellt einen bereit, löscht den Kopiekonstruktor explizit (um das Klonen zu verhindern) oder eine der Basisklassen oder Membervariablen wird gelöscht oder nicht zugänglich (privat). In den meisten Fällen, in denen ein angepasster Kopierkonstruktor erforderlich ist (z. B. Referenzzählung , tiefe Kopie von Zeigern), müssen auch der Destruktor und der Kopierzuweisungsoperator angepasst werden . Dies wird allgemein als die Dreierregel bezeichnet .

C#

Beispiel für einen C# -Konstruktor:

public class MyClass
{
    private int a;
    private string b;

    // Constructor
    public MyClass() : this(42, "string")
    {
    }

    // Overloading a constructor
    public MyClass(int a, string b)
    {
        this.a = a;
        this.b = b;
    }
}
// Code somewhere
// Instantiating an object with the constructor above
MyClass c = new MyClass(42, "string");

Statischer C#-Konstruktor

In C# ist ein statischer Konstruktor ein statischer Dateninitialisierer. Statische Konstruktoren werden auch Klassenkonstruktoren genannt . Da die erzeugte Methode den Namen .cctor trägt, werden sie oft auch als "cctors" bezeichnet.

Statische Konstruktoren ermöglichen die Initialisierung komplexer statischer Variablen. Statische Konstruktoren werden beim ersten Zugriff auf die Klasse implizit aufgerufen. Jeder Aufruf einer Klasse (statischer oder Konstruktoraufruf) löst die Ausführung des statischen Konstruktors aus. Statische Konstruktoren sind threadsicher und implementieren ein Singleton-Muster . Bei Verwendung in einer generischen Programmierklasse werden statische Konstruktoren bei jeder neuen generischen Instanziierung aufgerufen, einer pro Typ. Statische Variablen werden ebenfalls instanziiert.

public class MyClass
{
    private static int _A;

    // Normal constructor
    static MyClass()
    {
        _A = 32;
    }

    // Standard default constructor
    public MyClass()
    {

    }
}
// Code somewhere
// Instantiating an object with the constructor above
// right before the instantiation
// The variable static constructor is executed and _A is 32
MyClass c = new MyClass();

CFML

CFML verwendet eine Methode namens ' init' als Konstruktormethode.

Käse.cfc

component {
   // properties
   property name="cheeseName";

   // constructor
   function Cheese init( required string cheeseName ) {
      variables.cheeseName = arguments.cheeseName;
      return this;
   }
}

Erstellen Sie eine Käseinstanz.

myCheese = new Cheese( 'Cheddar' );

Seit ColdFusion 10 unterstützt CFML auch die Angabe des Namens der Konstruktormethode:

component initmethod="Cheese" {
   // properties
   property name="cheeseName";

   // constructor
   function Cheese Cheese( required string cheeseName ) {
      variables.cheeseName = arguments.cheeseName;
      return this;
   }
}

Eiffel

In Eiffel werden die Routinen, die neue Objekte initialisieren, Erzeugungsprozeduren genannt . Erstellungsverfahren haben die folgenden Eigenschaften:

  • Erstellungsprozeduren haben keinen expliziten Rückgabetyp (per Definition der Prozedur ).
  • Erstellungsverfahren werden benannt.
  • Erstellungsprozeduren werden im Text der Klasse namentlich als Erstellungsprozeduren bezeichnet.
  • Erstellungsprozeduren können explizit aufgerufen werden, um vorhandene Objekte neu zu initialisieren.
  • Jede effektive (dh konkrete oder nicht abstrakte) Klasse muss mindestens eine Erzeugungsprozedur bezeichnen.
  • Erstellungsprozeduren müssen das neu initialisierte Objekt in einem Zustand belassen, der die Klasseninvariante erfüllt.

Obwohl die Objekterstellung einige Feinheiten beinhaltet, besteht die Erstellung eines Attributs mit einer typischen Deklaration, x: Twie sie in einer Erstellungsanweisung ausgedrückt wird, create x.makeaus der folgenden Abfolge von Schritten:

  • Erstellen Sie eine neue direkte Instanz vom Typ T.
  • Führen Sie den Erstellungsvorgang makefür die neu erstellte Instanz aus.
  • Hängen Sie das neu initialisierte Objekt an die Entität an x.

Im ersten Snippet unten wird die Klasse POINTdefiniert. Die Prozedur makewird nach dem Schlüsselwort codiert feature.

Das Schlüsselwort createführt eine Liste von Prozeduren ein, die verwendet werden können, um Instanzen zu initialisieren. In diesem Fall enthält die Liste default_create, eine Prozedur mit einer leeren Implementierung, die von der Klasse geerbt wurde ANY, und die makeProzedur, die in der Klasse codiert ist.

class
    POINT
create
    default_create, make

feature

    make (a_x_value: REAL; a_y_value: REAL)
        do
            x := a_x_value
            y := a_y_value
        end

    x: REAL
            -- X coordinate

    y: REAL
            -- Y coordinate
        ...

Im zweiten Ausschnitt hat eine Klasse, die ein Client für POINTist, eine Deklaration my_point_1und den my_point_2Typ POINT.

Im prozeduralen Code my_point_1wird als Ursprung (0.0, 0.0) erstellt. Da keine Erstellungsprozedur angegeben ist, wird die default_createvon der Klasse geerbte Prozedur ANYverwendet. Diese Zeile könnte codiert sein create my_point_1.default_create. In einer Anweisung mit dem createSchlüsselwort können nur Prozeduren verwendet werden, die als Erstellungsprozeduren bezeichnet werden . Als nächstes folgt eine Erstellungsanweisung für my_point_2, die Anfangswerte für die my_point_2Koordinaten von . Die dritte Anweisung führt einen gewöhnlichen Instanzaufruf an die makeProzedur aus, um die Instanz, die my_point_2mit unterschiedlichen Werten verbunden ist , neu zu initialisieren .

    my_point_1: POINT
    my_point_2: POINT
        ...

            create my_point_1
            create my_point_2.make (3.0, 4.0)
            my_point_2.make (5.0, 8.0)
        ...

F#

In F# kann ein Konstruktor beliebige letoder do-Anweisungen enthalten, die in einer Klasse definiert sind. letAnweisungen definieren private Felder und doAnweisungen führen Code aus. Mit dem newSchlüsselwort können weitere Konstruktoren definiert werden .

type MyClass(_a : int, _b : string) = class
    // Primary constructor
    let a = _a
    let b = _b
    do printfn "a = %i, b = %s" a b

    // Additional constructors
    new(_a : int) = MyClass(_a, "") then
        printfn "Integer parameter given"

    new(_b : string) = MyClass(0, _b) then
        printfn "String parameter given"

    new() = MyClass(0, "") then
        printfn "No parameter given"
end
// Code somewhere
// instantiating an object with the primary constructor
let c1 = new MyClass(42, "string")

// instantiating an object with additional constructors
let c2 = new MyClass(42)
let c3 = new MyClass("string")
let c4 = MyClass() // "new" keyword is optional

Java

In Java unterscheiden sich Konstruktoren von anderen Methoden dadurch, dass:

  • Konstruktoren haben nie einen expliziten Rückgabetyp.
  • Konstruktoren können nicht direkt aufgerufen werden (das Schlüsselwort „ new“ ruft sie auf).
  • Konstruktoren sollten keine Nichtzugriffsmodifikatoren haben.

Java-Konstruktoren führen die folgenden Aufgaben in der folgenden Reihenfolge aus:

  1. Rufen Sie den Standardkonstruktor der Oberklasse auf, wenn kein Konstruktor definiert ist.
  2. Initialisieren Sie Membervariablen mit den angegebenen Werten.
  3. Führt den Rumpf des Konstruktors aus.

Java erlaubt Benutzern, einen Konstruktor in einem anderen Konstruktor mit einem this()Schlüsselwort aufzurufen . Aber this()muss erste Anweisung sein.

class Example
{ 
    Example() // Non-parameterized constructor
    {
        this(1);  // Calling of constructor
        System.out.println("0-arg-cons");
    }
    Example(int a) // Parameterized constructor
    {
        System.out.println("1-arg-cons");
    }
}
public static void main(String[] args)
{
  Example e = new Example();
}

Java bietet über das Schlüsselwort Zugriff auf den Konstruktor der Oberklassesuper .

public class Example
{
    // Definition of the constructor.
    public Example()
    {
        this(1);
    }

    // Overloading a constructor
    public Example(int input)
    {
        data = input; // This is an assignment
    }

    // Declaration of instance variable(s).
    private int data;
}
// Code somewhere else
// Instantiating an object with the above constructor
Example e = new Example(42);

Ein Konstruktor, der null Argumente verwendet, wird als "keine Argumente" oder "keine Argumente" Konstruktor bezeichnet.

JavaScript

Ab ES6 verfügt JavaScript wie viele andere Programmiersprachen über direkte Konstruktoren. Sie sind so geschrieben

class FooBar {
  constructor(baz) {
    this.baz = baz
  }
}

Dies kann als solche instanziiert werden

const foo = new FooBar('7')

Das Äquivalent dazu vor ES6 war das Erstellen einer Funktion, die ein Objekt als solches instanziiert

function FooBar (baz) {
  this.baz = baz;
}

Dies wird auf die gleiche Weise wie oben instanziiert.

Objekt Pascal

In Object Pascal ähnelt der Konstruktor einer Factory-Methode . Der einzige syntaktische Unterschied zu regulären Methoden ist das Schlüsselwort constructorvor dem Namen (anstelle von procedureoder function). Es kann einen beliebigen Namen haben, obwohl die Konvention Createals Präfix verwendet werden soll, z. B. in CreateWithFormatting. Das Erstellen einer Instanz einer Klasse funktioniert wie das Aufrufen einer statischen Methode einer Klasse: TPerson.Create('Peter').

program OopProgram;

type
  TPerson = class
  private
    FName: string;
  public
    property Name: string read FName;
    constructor Create(AName: string);
  end;

constructor TPerson.Create(AName: string);
begin
  FName := AName;
end;

var
  Person: TPerson;
begin
  Person := TPerson.Create('Peter'); // allocates an instance of TPerson and then calls TPerson.Create with the parameter AName = 'Peter'
end.

OCaml

In OCaml gibt es einen Konstruktor. Parameter werden direkt nach dem Klassennamen definiert. Sie können zum Initialisieren von Instanzvariablen verwendet werden und sind in der gesamten Klasse zugänglich. Eine anonyme versteckte Methode, die aufgerufen wird, initializerermöglicht es, einen Ausdruck sofort nach dem Erstellen des Objekts auszuwerten.

class person first_name last_name =
  object
    val full_name = first_name ^ " " ^ last_name

    initializer
      print_endline("Hello there, I am " ^ full_name ^ ".")

    method get_last_name = last_name
  end;;

let alonzo = new person "Alonzo" "Church" in (*Hello there, I am Alonzo Church.*)

print_endline alonzo#get_last_name (*Church*)

PHP

In PHP Version 5 und höher ist der Konstruktor eine Methode namens __construct()(beachten Sie, dass es sich um einen doppelten Unterstrich handelt), die das Schlüsselwort newnach dem Erstellen des Objekts automatisch aufruft. Es wird normalerweise verwendet, um Initialisierungen wie Eigenschafteninitialisierungen automatisch durchzuführen. Konstruktoren können auch Argumente akzeptieren. In diesem Fall müssen Sie beim newSchreiben der Anweisung auch die Konstruktorargumente für die Parameter senden.

class Person
{
    private string $name;

    public function __construct(string $name): void
    {
        $this->name = $name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

Perl 5

In der Programmiersprache Perl Version 5 sind Konstruktoren standardmäßig Factory-Methoden , dh Methoden, die das Objekt erstellen und zurückgeben, was konkret bedeutet, eine gesegnete Referenz zu erstellen und zurückzugeben. Ein typisches Objekt ist eine Referenz auf einen Hash, obwohl selten auch Referenzen auf andere Typen verwendet werden. Konventionsgemäß heißt der einzige Konstruktor new , obwohl es erlaubt ist, ihn anders zu benennen oder mehrere Konstruktoren zu haben. Beispielsweise kann eine Person-Klasse einen Konstruktor namens new sowie einen Konstruktor new_from_file haben, der eine Datei für Person-Attribute liest, und new_from_person, der ein anderes Person-Objekt als Vorlage verwendet.

package Person;
# In Perl constructors are named 'new' by convention.
sub new {
    # Class name is implicitly passed in as 0th argument.
    my $class = shift;

    # Default attribute values, if you have any.
    my %defaults = ( foo => "bar" );

    # Initialize attributes as a combination of default values and arguments passed.
    my $self = { %defaults, @_ };

    # Check for required arguments, class invariant, etc.
    if ( not defined $self->{first_name} ) {
        die "Mandatory attribute missing in Person->new(): first_name";
    }
    if ( not defined $self->{last_name} ) {
        die "Mandatory attribute missing in Person->new(): last_name";
    }
    if ( defined $self->{age} and $self->{age} < 18 ) {
        die "Invalid attribute value in Person->new(): age < 18";
    }

    # Perl makes an object belong to a class by 'bless'.
    bless $self, $class;
    return $self;
}
1;

Perl 5 mit Elch

Beim Moose-Objektsystem für Perl kann der Großteil dieses Boilerplates weggelassen werden, ein Standard wird neu erstellt, Attribute können angegeben werden, sowie ob diese gesetzt, zurückgesetzt oder benötigt werden. Darüber hinaus kann jede zusätzliche Konstruktorfunktionalität in eine BUILD- Methode aufgenommen werden, die der von Moose generierte Konstruktor aufruft, nachdem er die Argumente überprüft hat. Eine BUILDARGS- Methode kann angegeben werden, um Konstruktorargumente zu behandeln, die nicht in Hashref / Schlüssel => Wertform vorliegen.

package Person;
# enable Moose-style object construction
use Moose;

# first name ( a string) can only be set at construction time ('ro')
has first_name => (is => 'ro', isa => 'Str', required => 1);
# last name ( a string) can only be set at construction time ('ro')
has last_name  => (is => 'ro', isa => 'Str', required => 1);
# age (Integer) can be modified after construction ('rw'), and is not required
# to be passed to be constructor.  Also creates a 'has_age' method which returns
# true if age has been set
has age        => (is => 'rw', isa => 'Int', predicate => 'has_age');

# Check custom requirements
sub BUILD {
      my $self = shift;
      if ($self->has_age && $self->age < 18) { # no under 18s
           die "No under-18 Persons";
      }
}
1;

In beiden Fällen wird die Person-Klasse wie folgt initiiert:

use Person;
my $p = Person->new( first_name => 'Sam', last_name => 'Ashe', age => 42 );

Python

In Python werden Konstruktoren durch eine oder beide Methoden __new__und definiert __init__. Eine neue Instanz wird erstellt, indem die Klasse aufgerufen wird, als ob es eine Funktion wäre, die die Methoden __new__und aufruft __init__. Wenn in der Klasse keine Konstruktormethode definiert ist, wird die nächste in der Methodenauflösungsreihenfolge der Klasse gefunden .

Im typischen Fall muss nur die __init__Methode definiert werden. (Die häufigste Ausnahme sind unveränderliche Objekte.)

>>> class ExampleClass:
...     def __new__(cls, value):
...         print("Creating new instance...")
...         # Call the superclass constructor to create the instance.
...         instance = super(ExampleClass, cls).__new__(cls)
...         return instance
...     def __init__(self, value):
...         print("Initialising instance...")
...         self.payload = value
>>> exampleInstance = ExampleClass(42)
Creating new instance...
Initialising instance...
>>> print(exampleInstance.payload)
42

Klassen fungieren normalerweise als Fabriken für neue Instanzen von sich selbst, dh eine Klasse ist ein aufrufbares Objekt (wie eine Funktion), wobei der Aufruf der Konstruktor ist, und der Aufruf der Klasse gibt eine Instanz dieser Klasse zurück. Die __new__Methode darf jedoch für spezielle Zwecke etwas anderes als eine Instanz der Klasse zurückgeben. In diesem Fall wird das __init__nicht aufgerufen.

Raku

Mit Raku kann noch mehr Boilerplate weggelassen werden, da eine neue Standardmethode vererbt wird, Attribute angegeben werden können sowie ob sie gesetzt, zurückgesetzt oder benötigt werden können. Darüber hinaus kann jede zusätzliche Konstruktorfunktionalität in eine BUILD- Methode aufgenommen werden, die aufgerufen wird, um eine benutzerdefinierte Initialisierung zu ermöglichen. Eine TWEAK- Methode kann angegeben werden, um alle bereits (implizit) initialisierten Attribute nachzubearbeiten .

class Person {
    has Str $.first-name is required; # First name (a string) can only be set at
                                      # construction time (the . means "public").
    has Str $.last-name is required;  # Last name (a string) can only be set at
                                      # construction time (a ! would mean "private").
    has Int $.age is rw;              # Age (an integer) can be modified after 
                                      # construction ('rw'), and is not required
                                      # during the object instantiation.
    
    # Create a 'full-name' method which returns the person's full name.
    # This method can be accessed outside the class.
    method full-name { $!first-name.tc ~ " " ~ $!last-name.tc }

    # Create a 'has-age' method which returns true if age has been set.
    # This method is used only inside the class so it's declared as "private"
    # by prepending its name with a !
    method !has-age { self.age.defined }
  
    # Check custom requirements
    method TWEAK {
        if self!has-age && $!age < 18 { # No under 18
            die "No person under 18";
        }
    }
}

Die Person-Klasse wird wie folgt instanziiert:

my $p0 = Person.new( first-name => 'Sam', last-name => 'Ashe', age => 42 );
my $p1 = Person.new( first-name => 'grace', last-name => 'hopper' );
say $p1.full-name(); # OUTPUT: «Grace Hopper␤»

Alternativ können die benannten Parameter mit der Doppelpunkt-Paar-Syntax in Perl 6 angegeben werden:

my $p0 = Person.new( :first-name<Sam>, :last-name<Ashe>, :age(42) );
my $p1 = Person.new( :first-name<Grace>, :last-name<Hopper> );

Und sollten Sie Variablen mit identischen Namen wie die benannten Parameter eingerichtet haben, können Sie eine Verknüpfung verwenden, die den Namen der Variablen für den benannten Parameter verwendet:

my $first-name = "Sam";
my $last-name  = "Ashe";
my $age        = 42;
my $p0 = Person.new( :$first-name, :$last-name, :$age );

Rubin

In Ruby werden Konstruktoren durch die Definition einer Methode namens initialize. Diese Methode wird ausgeführt, um jede neue Instanz zu initialisieren.

irb(main):001:0> class ExampleClass
irb(main):002:1>   def initialize
irb(main):003:2>     puts "Hello there"
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> ExampleClass.new
Hello there
=> #<ExampleClass:0x007fb3f4299118>

Visual Basic .NET

In Visual Basic .NET verwenden Konstruktoren eine Methodendeklaration mit dem Namen " New".

Class Foobar
    Private strData As String

    ' Constructor
    Public Sub New(ByVal someParam As String)
        strData = someParam
    End Sub
End Class
' code somewhere else
' instantiating an object with the above constructor
Dim foo As New Foobar(".NET")

Siehe auch

Anmerkungen

Verweise