В объектно-ориентированном программировании на основе классов конструктор (сокращение: ctor ) — это специальный тип функции , вызываемый для создания объекта . Он подготавливает новый объект к использованию, часто принимая аргументы , которые конструктор использует для установки требуемых переменных -членов .
Конструктор похож на метод экземпляра , но отличается от метода тем, что не имеет явного возвращаемого типа , не наследуется неявно и обычно имеет другие правила для модификаторов области действия. Конструкторы часто имеют то же имя, что и объявляющий класс . Их задача — инициализировать элементы данных объекта и установить инвариант класса , завершаясь неудачей, если инвариант недействителен. Правильно написанный конструктор оставляет результирующий объект в допустимом состоянии. Неизменяемые объекты должны быть инициализированы в конструкторе.
Большинство языков допускают перегрузку конструктора, так как для класса может быть более одного конструктора с разными параметрами. Некоторые языки учитывают некоторые специальные типы конструкторов. Конструкторы, которые конкретно используют один класс для создания объектов и возвращают новый экземпляр класса, абстрагируются фабриками , которые также создают объекты, но могут делать это разными способами, используя несколько классов или разные схемы распределения, такие как пул объектов .
Конструкторы, которые могут принимать хотя бы один аргумент, называются параметризованными конструкторами. Когда объект объявляется в параметризованном конструкторе, начальные значения должны быть переданы в качестве аргументов функции конструктора. Обычный способ объявления объекта может не работать. Конструкторы могут вызываться явно или неявно. Метод неявного вызова конструктора также называется сокращенным методом.
class Example { public : Example (); Example ( int a , int b ); // Параметризованный конструктор. частный : int x_ ; int y_ ; }; Пример :: Пример () = по умолчанию ; Пример :: Пример ( int x , int y ) : x_ ( x ), y_ ( y ) {}
Пример e = Пример ( 0 , 50 ); // Явный вызов. Пример e2 ( 0 , 50 ); // Неявный вызов.
Если программист не предоставляет конструктор для инстанцируемого класса, компилятор Java вставляет конструктор по умолчанию в ваш код от вашего имени. Этот конструктор известен как конструктор по умолчанию. Вы не найдете его в исходном коде (файле java), так как он будет вставлен в код во время компиляции и существует в файле .class. Поведение конструктора по умолчанию зависит от языка. Он может инициализировать члены данных нулем или другими такими же значениями, или может вообще ничего не делать. В Java «конструктор по умолчанию» относится к конструктору nullary, который автоматически генерируется компилятором, если для класса не были определены конструкторы или при отсутствии каких-либо конструкторов, определенных программистом (например, в Java конструктор по умолчанию неявно вызывает конструктор nullary суперкласса, а затем выполняет пустое тело). Все поля остаются с их начальным значением 0 (целые типы), 0.0 (типы с плавающей точкой), false (логический тип) или null (ссылочные типы)...
#include <iostream> class Student { public : Student ( int a = 0 , int b = 0 ); // Конструктор по умолчанию. целое а ; целое б ; };
Как и C++, Java также поддерживает «Copy Constructor». Но, в отличие от C++, Java не создает конструктор копирования по умолчанию, если вы не напишете свой собственный. Конструкторы копирования определяют действия, выполняемые компилятором при копировании объектов класса. Конструктор копирования имеет один формальный параметр, который является типом класса (параметр может быть ссылкой на объект). Он используется для создания копии существующего объекта того же класса. Несмотря на то, что оба класса одинаковы, он считается конструктором преобразования. Хотя конструкторы копирования обычно сокращаются как copy ctor или cctor, они не имеют ничего общего с конструкторами классов, используемыми в .NET с использованием той же аббревиатуры.
Конструкторы преобразования предоставляют компилятору возможность неявно создать объект, принадлежащий одному классу, на основе объекта другого типа. Эти конструкторы обычно вызываются неявно для преобразования аргументов или операндов в соответствующий тип, но их также можно вызывать явно.
В C++ конструкторы перемещения принимают ссылку Rvalue на объект класса и используются для реализации передачи права собственности на ресурсы объекта параметра.
__construct
. Для обратной совместимости метод с тем же именем, что и у класса, будет вызван, если __construct
метод не может быть найден. Начиная с PHP 5.3.3, это работает только для классов без пространства имен. [1]__construct
. Методы с тем же именем, что и у класса, вызовут ошибку уровня E_DEPRECATED. [1]New
".__new__
" и " __init__
". __new__
Метод отвечает за выделение памяти для экземпляра и получает класс в качестве аргумента (обычно называемого " cls
"). __init__
Методу (часто называемому "инициализатором") передается вновь созданный экземпляр в качестве аргумента (обычно называемого " self
"). [2]constructor
» и могут иметь определяемые пользователем имена (но чаще всего называются « Create
»).alloc
" и " init
", причем alloc
метод резервирует (выделяет) память для экземпляра класса, а init
метод обрабатывает большую часть инициализации экземпляра. Вызов метода " new
" вызывает как методы , так alloc
и init
для экземпляра класса.В Java, C# и VB .NET конструктор создает объекты ссылочного типа в специальной структуре памяти, называемой « куча ». Типы значений (такие как int, double и т. д.) создаются в последовательной структуре, называемой « стек ». VB .NET и C# также позволяют использовать оператор new для создания объектов типа значения, но эти объекты типа значения создаются в стеке независимо от того, используется оператор или нет.
В C++ объекты создаются в стеке, когда конструктор вызывается без оператора new, и создаются в куче, когда конструктор вызывается с оператором new. Объекты стека удаляются неявно, когда они выходят из области видимости, в то время как объекты кучи должны быть удалены неявно деструктором или явно с помощью оператора delete .
Конструкторы реализованы в разных языках программирования разными способами, в том числе:
В C++ имя конструктора — это имя класса. Он ничего не возвращает. Он может иметь параметры, как и любая функция-член . Функции-конструкторы обычно объявляются в публичном разделе, но также могут быть объявлены в защищенном и закрытом разделах, если пользователь хочет ограничить доступ к ним.
Конструктор состоит из двух частей. Первая часть — это список инициализаторов , который следует за списком параметров и предшествует телу метода. Он начинается с двоеточия, а записи разделяются запятыми. Список инициализаторов не является обязательным, но дает возможность предоставить значения для членов данных и избежать отдельных операторов присваивания. Список инициализаторов необходим, если у вас есть константные или ссылочные члены данных или члены, которые не имеют логики конструктора без параметров. Назначения происходят в соответствии с порядком, в котором объявляются члены данных (даже если порядок в списке инициализаторов отличается). [3] Вторая часть — это тело, которое представляет собой обычное тело метода, заключенное в фигурные скобки.
C++ допускает более одного конструктора. Другие конструкторы должны иметь разные параметры. Кроме того, конструкторы, содержащие параметры, которым заданы значения по умолчанию, должны придерживаться ограничения, что не всем параметрам заданы значения по умолчанию. Это ситуация, которая имеет значение только в том случае, если есть конструктор по умолчанию. Конструктор базового класса (или базовых классов) также может быть вызван производным классом. Функции конструктора не наследуются, и на их адреса нельзя ссылаться. Когда требуется выделение памяти, операторы new и delete вызываются неявно.
Конструктор копирования имеет параметр того же типа, который передается как константная ссылка, например Vector(const Vector& rhs) . Если он не указан явно, компилятор использует конструктор копирования для каждой переменной-члена или просто копирует значения в случае примитивных типов. Реализация по умолчанию неэффективна, если класс имеет динамически выделенные члены (или обращается к другим ресурсам), поскольку это может привести к двойным вызовам удаления ( или двойному освобождению ресурсов) при уничтожении.
class Foobar { public : Foobar ( double r = 1.0 , double alpha = 0.0 ) // Конструктор, параметры со значениями по умолчанию. : x_ ( r * cos ( alpha )) // <- Список инициализаторов { y_ = r * sin ( alpha ); // <- Обычное присваивание } частный : двойной x_ ; двойной y_ ; };
Примеры вызовов:
Foobar а , б ( 3 ), в ( 5 , M_PI / 4 );
При возврате объектов из функций или передаче объектов по значению конструктор копирования объектов будет вызван неявно, если только не применяется оптимизация возвращаемого значения .
C++ неявно генерирует конструктор копирования по умолчанию, который будет вызывать конструкторы копирования для всех базовых классов и всех переменных-членов, если только программист не предоставит один, явно не удалит конструктор копирования (чтобы предотвратить клонирование) или один из базовых классов или переменных-членов конструктор копирования будет удален или недоступен (закрытый). В большинстве случаев, когда требуется настраиваемый конструктор копирования (например, подсчет ссылок , глубокое копирование указателей), также требуется настроить деструктор и оператор присваивания копирования . Это обычно называют правилом трех .
Пример конструктора C# :
открытый класс MyClass { частный int a ; частная строка b ; // Конструктор public MyClass () : this ( 42 , "string" ) { } // Перегрузка конструктора public MyClass ( int a , string b ) { this . a = a ; this . b = b ; } }
// Код где-нибудь // Создание экземпляра объекта с помощью конструктора выше MyClass c = new MyClass ( 42 , "string" );
В C# статический конструктор — это статический инициализатор данных. [4] : 111–112 Статические конструкторы также называются конструкторами классов . Поскольку фактически сгенерированный метод имеет имя .cctor, их часто также называют «cctors». [5] [6]
Статические конструкторы допускают сложную инициализацию статических переменных. [7] Статические конструкторы вызываются неявно при первом доступе к классу. Любой вызов класса (статический или вызов конструктора) запускает выполнение статического конструктора. Статические конструкторы потокобезопасны и реализуют шаблон singleton . При использовании в универсальном классе программирования статические конструкторы вызываются при каждом новом универсальном создании экземпляра, по одному на тип. [8] : 38 [4] : 111 Статические переменные также создаются.
открытый класс MyClass { частный статический int _A ; // Обычный конструктор static MyClass () { _A = 32 ; } // Стандартный конструктор по умолчанию public MyClass () { } }
// Код где-нибудь // Создание экземпляра объекта с помощью конструктора выше // прямо перед созданием экземпляра // Выполняется статический конструктор переменной, и _A равно 32 MyClass c = new MyClass ();
Язык разметки ColdFusion (CFML) использует метод с именем ' init
' в качестве метода конструктора.
Сыр.cfc
компонент { // свойства имя свойства = "cheeseName" ; // конструктор функция Cheese init ( требуется строка cheeseName ) { variables.cheeseName = arguments.cheeseName ; return this ; } }
Создать экземпляр сыра.
myCheese = новый сыр ( 'Чеддер' );
Начиная с ColdFusion 10, [9] CFML также поддерживает указание имени метода конструктора:
компонент initmethod = "Cheese" { // свойства имя свойства = "cheeseName" ; // конструктор функция Cheese Cheese ( требуется строка cheeseName ) { variables . cheeseName = arguments . cheeseName ; return this ; } }
В Eiffel процедуры, которые инициализируют новые объекты, называются процедурами создания . Процедуры создания имеют следующие черты:
Хотя создание объекта требует некоторых тонкостей, [10] создание атрибута с типичным объявлением x: T
, выраженным в инструкции по созданию, create x.make
состоит из следующей последовательности шагов:
T
. [c]make
для вновь созданного экземпляра.x
.В первом фрагменте ниже POINT
определяется класс. Процедура make
кодируется после ключевого слова feature
.
Ключевое слово create
вводит список процедур, которые могут быть использованы для инициализации экземпляров. В этом случае список включает default_create
, процедуру с пустой реализацией, унаследованную от класса ANY
, и make
процедуру, закодированную внутри класса.
класс POINT создать default_create , сделать особенность сделать ( a_x_value : REAL ; a_y_value : REAL ) сделать x := a_x_value y := a_y_value конец x : REAL -- Координата X y : REAL -- координата Y ...
Во втором фрагменте класс, который является клиентом, POINT
имеет объявления my_point_1
и my_point_2
типа POINT
.
В процедурном коде my_point_1
создается как начало отсчета (0.0, 0.0). Поскольку процедура создания не указана, используется процедура, default_create
унаследованная от класса . Эта строка могла быть закодирована как . Только процедуры, названные процедурами создания, могут использоваться в инструкции с ключевым словом . Далее следует инструкция создания для , предоставляющая начальные значения для координат . Третья инструкция делает обычный вызов экземпляра для процедуры для повторной инициализации экземпляра, прикрепленного к , с другими значениями.ANY
create my_point_1.default_create
create
my_point_2
my_point_2
make
my_point_2
my_point_1 : ТОЧКА my_point_2 : ТОЧКА ... создать мою_точку_1 создать мою_точку_2 . сделать ( 3.0 , 4.0 ) мою_точку_2 . сделать ( 5.0 , 8.0 ) ...
В F# конструктор может включать любые let
или do
операторы, определенные в классе. let
операторы определяют закрытые поля, а do
операторы выполняют код. Дополнительные конструкторы могут быть определены с помощью new
ключевого слова.
type MyClass (_ a : int , _ b : string ) = class // Основной конструктор let a = _ a let b = _ b do printfn "a = %i, b = %s" a b // Дополнительные конструкторы new (_ a : int ) = MyClass (_ a , "" ) then printfn "Дан целочисленный параметр" new (_ b : string ) = MyClass ( 0 , _ b ) then printfn "Дан параметр String" new () = MyClass ( 0 , "" ) then printfn "Параметр не указан" end
// Код где-нибудь // создание экземпляра объекта с помощью первичного конструктора let c1 = new MyClass ( 42 , "string" ) // создание экземпляра объекта с дополнительными конструкторами let c2 = new MyClass ( 42 ) let c3 = new MyClass ( "string" ) let c4 = MyClass () // ключевое слово "new" необязательно
В Java конструкторы отличаются от других методов тем, что:
new
» вызывает их).Конструкторы Java выполняют следующие задачи в следующем порядке:
Java позволяет пользователям вызывать один конструктор в другом конструкторе с помощью this()
ключевого слова. Но this()
это должно быть первым оператором. [11]
class Example { Example () // Непараметризованный конструктор { this ( 1 ); // Вызов конструктора System.out.println ( "0-arg-cons" ) ; } Example ( int a ) // Параметризованный конструктор { System.out.println ( "1-arg-cons" ) ; } } public static void main ( String [ ] args ) { Example e = new Example ( ) ; }
Java предоставляет доступ к конструктору суперкласса через super
ключевое слово.
public class Example { // Определение конструктора. public Example () { this ( 1 ); } // Перегрузка конструктора public Example ( int input ) { data = input ; // Это присваивание } // Объявление переменных экземпляра. private int data ; }
// Код в другом месте // Создание экземпляра объекта с помощью приведенного выше конструктора Пример e = new Пример ( 42 );
Конструктор, принимающий нулевое количество аргументов, называется конструктором «без аргументов» или «без аргументов». [12]
Начиная с ES6, JavaScript имеет прямые конструкторы, как и многие другие языки программирования. Они пишутся так
класс FooBar { конструктор ( baz ) { этот . baz = baz } }
Это может быть реализовано следующим образом:
const foo = new FooBar ( '7' )
Эквивалентом этого до ES6 было создание функции, которая создавала экземпляр объекта как такового.
функция FooBar ( baz ) { this . baz = baz ; }
Это реализуется таким же образом, как описано выше.
В Object Pascal конструктор похож на метод factory . Единственное синтаксическое отличие от обычных методов — это ключевое слово constructor
перед именем (вместо procedure
или function
). Он может иметь любое имя, хотя соглашение заключается в том, чтобы иметь Create
префикс as , например, в CreateWithFormatting
. Создание экземпляра класса работает как вызов статического метода класса: TPerson.Create('Peter')
.
программа OopProgram ; тип TPerson = класс private FName : string ; публичное свойство Name : string read FName ; конструктор Create ( AName : string ) ; конец ; конструктор TPerson.Create ( AName : string ) ; begin FName : = AName ; end ; var Person : TPerson ; begin Person := TPerson . Create ( 'Peter' ) ; // выделяет экземпляр TPerson и затем вызывает TPerson.Create с параметром AName = 'Peter' end .
В OCaml есть один конструктор. Параметры определяются сразу после имени класса. Они могут использоваться для инициализации переменных экземпляра и доступны во всем классе. Анонимный скрытый метод, называемый initializer
позволяет вычислить выражение сразу после построения объекта. [13]
класс человек имя_фамилия = объект значение полное_имя = имя ^ " " ^ фамилия инициализатор print_endline ( "Привет, я " ^ full_name ^ "." ) метод get_last_name = last_name конец ;;пусть алонзо = новый человек "Алонзо" "Черч" в (*Привет, я Алонзо Черч.*)print_endline alonzo # get_last_name (*Церковь*)
В PHP версии 5 и выше конструктор — это метод с именем __construct()
(обратите внимание, что это двойное подчеркивание), который new
автоматически вызывается ключевым словом после создания объекта. Обычно он используется для автоматического выполнения инициализации, например инициализации свойств. Конструкторы также могут принимать аргументы, и в этом случае при new
написании оператора вам также необходимо отправить аргументы конструктора для параметров. [1]
класс Person { частная строка $name ; публичная функция __construct ( string $name ) : void { $this -> name = $name ; } публичная функция getName () : string { return $this -> name ; } }
В PHP классу разрешено объявлять максимум один метод-конструктор. Статические методы, фабричные классы или необязательные аргументы конструктора — это некоторые способы облегчить создание нескольких способов объектов класса PHP.
В Perl версии 5 по умолчанию конструкторы являются фабричными методами , то есть методами, которые создают и возвращают объект, конкретно означая создание и возврат благословенной ссылки. Типичный объект — это ссылка на хэш, хотя редко используются ссылки на другие типы. По соглашению единственный конструктор называется new , хотя разрешено называть его иначе или иметь несколько конструкторов. Например, класс Person может иметь конструктор с именем new и конструктор new_from_file , который считывает файл для атрибутов Person, и new_from_person , который использует другой объект Person в качестве шаблона.
package Person ; # В Perl конструкторы по соглашению называются «new». sub new { # Имя класса неявно передается как 0-й аргумент. my $class = shift ; # Значения атрибутов по умолчанию, если таковые имеются. my %defaults = ( foo => "bar" ); # Инициализируем атрибуты как комбинацию значений по умолчанию и переданных аргументов. my $self = { %defaults , @_ }; # Проверка обязательных аргументов, инварианта класса и т. д. if ( not defined $self -> { first_name } ) { die "В Person->new() отсутствует обязательный атрибут: first_name" ; } if ( not defined $self -> { last_name } ) { die "В Person->new() отсутствует обязательный атрибут: last_name" ; } if ( defined $self -> { age } and $self -> { age } < 18 ) { die "Недопустимое значение атрибута в Person->new(): age < 18" ; } # Perl делает объект принадлежащим классу с помощью 'bless'. bless $self , $class ; return $self ; } 1 ;
В объектной системе Moose для Perl большую часть этого шаблона можно опустить, создается new по умолчанию, можно указать атрибуты и можно ли их устанавливать, сбрасывать или они обязательны. Кроме того, любые дополнительные функции конструктора можно включить в метод BUILD , который вызовет сгенерированный Moose конструктор после проверки аргументов. Можно указать метод BUILDARGS для обработки аргументов конструктора не в форме hashref / key => value.
package Person ; # включить создание объектов в стиле Moose use Moose ; # имя (строка) может быть установлено только во время построения ('ro') has first_name => ( is => 'ro' , isa => 'Str' , required => 1 ); # фамилия (строка) может быть установлена только во время построения ('ro') has last_name => ( is => 'ro' , isa => 'Str' , required => 1 ); # возраст (целое число) может быть изменен после построения ('rw') и не требуется # для передачи в конструктор. Также создает метод 'has_age', который возвращает # true, если возраст был установлен has age => ( is => 'rw' , isa => 'Int' , predicate => 'has_age' ); # Проверка пользовательских требований sub BUILD { my $self = shift ; if ( $self -> has_age && $self -> age < 18 ) { # нет лиц моложе 18 лет die "No under-18 Persons" ; } } 1 ;
В обоих случаях класс Person инициируется следующим образом:
использовать Person ; my $p = Person -> new ( first_name => 'Сэм' , last_name => 'Эш' , age => 42 );
В Python конструкторы определяются одним или обоими методами __new__
и __init__
. Новый экземпляр создается путем вызова класса, как если бы это была функция, которая вызывает методы __new__
и . Если метод конструктора не определен в классе, будет вызван следующий метод, найденный в порядке разрешения методов__init__
класса . [14]
В типичном случае __init__
необходимо определить только метод. (Наиболее распространенное исключение — неизменяемые объекты.)
>>> class ExampleClass : ... def __new__ ( cls , value ): ... print ( "Создание нового экземпляра..." ) ... # Вызвать конструктор суперкласса для создания экземпляра. ... instance = super ( ExampleClass , cls ) . __new__ ( cls ) ... return instance ... def __init__ ( self , value ): ... print ( "Инициализация экземпляра..." ) ... self . payload = value >>> exampleInstance = ExampleClass ( 42 ) Создание нового экземпляра... Инициализация экземпляра... >>> print ( exampleInstance . payload ) 42
Классы обычно действуют как фабрики для новых экземпляров самих себя, то есть класс является вызываемым объектом (как функция), при этом вызов является конструктором, а вызов класса возвращает экземпляр этого класса. Однако методу __new__
разрешено возвращать что-то иное, чем экземпляр класса, для специальных целей. В этом случае __init__
не вызывается. [15]
В Raku можно опустить еще больше шаблонного кода, учитывая, что новый метод по умолчанию наследуется, атрибуты могут быть указаны, и могут ли они быть установлены, сброшены или являются обязательными. Кроме того, любые дополнительные функции конструктора могут быть включены в метод BUILD , который будет вызван для обеспечения пользовательской инициализации. Метод TWEAK может быть указан для постобработки любых атрибутов, которые уже (неявно) инициализированы.
class Person { has Str $.first-name is required ; # Имя (строка) может быть задано только во время # построения (точка . означает "public"). has Str $.last-name is required ; # Фамилия (строка) может быть задана только во время # построения (точка ! будет означать "private"). has Int $.age is rw ; # Возраст (целое число) может быть изменен после # построения ('rw') и не требуется # во время создания объекта. # Создайте метод 'full-name', который возвращает полное имя человека. # К этому методу можно получить доступ вне класса. method full-name { $!first-name . tc ~ " " ~ $!last-name . tc } # Создайте метод 'has-age', который возвращает true, если возраст установлен. # Этот метод используется только внутри класса, поэтому он объявлен как "private" # путем добавления к его имени префикса ! method ! has-age { self . age . defined } # Проверка пользовательских требований method TWEAK { if self ! has-age && $!age < 18 { # Нет лиц моложе 18 лет die "Нет лиц моложе 18 лет" ; } }}
Экземпляр класса Person создается следующим образом:
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 (); # ВЫВОД: «Grace Hopper»
В качестве альтернативы именованные параметры можно указать с помощью синтаксиса двоеточия в Perl 6:
my $p0 = Person.new (: first-name <Sam> , : last-name <Ashe> , : age ( 42 )); my $ p1 = Person.new (: first-name <Grace> , : last-name <Hopper> ) ;
А если вы настроили переменные с именами, идентичными именованным параметрам, вы можете использовать сокращение, которое будет использовать имя переменной для именованного параметра:
мое $first-name = "Сэм" ; мое $last-name = "Эш" ; мой $age = 42 ; мой $p0 = Person . new ( : $first-name , : $last-name , : $age );
В Ruby конструкторы создаются путем определения метода с именем initialize
. Этот метод выполняется для инициализации каждого нового экземпляра.
irb(main):001:0> class ExampleClass irb(main):002:1> def initialize irb(main):003:2> puts "Привет" irb(main):004:2> end irb(main):005:1> end => nil irb(main):006:0> ExampleClass . new Привет => #<ExampleClass:0x007fb3f4299118>
В Visual Basic .NET конструкторы используют объявление метода с именем " New
".
Класс Foobar Private strData как строка ' Конструктор Public Sub New ( ByVal someParam As String ) strData = someParam End Sub End Class
' код где-то еще ' создание экземпляра объекта с помощью приведенного выше конструктора Dim foo As New Foobar ( ".NET" )