建構子

在類別基礎的物件導向程式設計中，**建構子**（英語： **Constructor**，有時簡稱 ctor），別稱：**構造方法**、**建構式**、**建構子、建構式**）是一個類別裡用於建立物件的特殊子程式。它能初始化一個新建的物件，並時常會接受參數用以設定實例變數。

建構子跟一般的實例方法十分相似；但是與其它方法不同，建構子沒有回傳型別，不會被繼承，且不會有範圍修飾詞。建構子的函式名稱一般與它所屬的類別的名稱相同。 它承擔著初始化物件資料成員並建立類不變象的任務；在類別不變象無效的時候它會失敗。一個正確編寫的建構子會使它生成的物件保持在一個_有效_狀態。不可變物件必須在建構子內完成所有初始化。

多數程式語言允許建構子多載 - 一個類別被允許擁有多個接受不同參數種類的建構子同時存在。一些程式語言允許某些特殊種類的建構子。使用單個類別來具體地建立和返回新實例的建構子，時常被抽象為工廠方法 - 一種同樣用來建立新物件，但會同時使用多個類別，或者一些諸如物件池的分配方案來完成這一過程的子程式。

## 種類

### 參數化建構子

接收參數的建構子被稱為**參數化建構子**。參數的數量可以大於或等於一。例如，在 C++ 中：

使用參數化建構子聲明物件時，必須傳入初始值作為建構子的參數。在這種情況下，一般的聲明物件的方法可能不再適用。
建構子函式的呼叫方式可以分為顯式和隱式兩種。

### 預設建構子

如果在編寫一個可實例化的類時沒有專門編寫建構子，多數程式語言會自動生成預設建構子。

預設建構子的特性依不同語言而定。某些情況下它會將所有的實例變數同時初始化到 0，或者任何其他別的值；某些預設建構子什麼也不會做。

某些語言 (Java, C#, VB .NET) 會預設構造由該類類型定義的陣列，使其充滿空值參照。沒有空值參照的語言一般會禁止預設構造包含不可預設構造物件的陣列，或者要求在建立時專門初始化這些數值 (C++):

### 轉換建構子

轉換建構子可定義從使用者定義或內建類型轉換成使用者定義類型的作業。

### 複製建構子

複製建構子（英語：Copy constructor）是 C++ 程式語言中的一種特別的建構子，習慣上用來建立一個全新的物件，這個全新的物件相當於已存在物件的副本。這個建構子只有一個參數（引數）：就是用來複製物件的參照（常用 const 修飾）。建構子也可以有更多的參數，但除了最左第一個參數是該類別的參照類別型外，其它參數必須有預設值。

### 移動建構子

移動建構式（英語：Move constructor）是 C++11 中新增的一種建構式，用來避免多餘的分配新記憶體 —— 複製 —— 銷毀舊記憶體的操作。參見 C++11 條目內的介紹。

## 語法

* Java, C++, C#, ActionScript 和 PHP 4 中的命名規範會要求建構子函式的名稱與它所在類的名稱相同。
* PHP 5 建議的建構子函式名稱為 `__construct`。為了保證向下相容，`__construct` 方法無法找到時會呼叫任何跟類名同名的方法作為建構子。從 PHP 5.3.3 起，這種途徑只對非命名空間的類有效。
* 在 Perl 裡，建構子被約定俗成地命名為 "new"，並且會完成建立物件的大量工作。
* 在 Perl 的 Moose 物件系統中，建構式（叫做 _new_）是自動生成的，程式設計師可以通過指定一個 _BUILD_ 方法來對其進行擴充。
* 在 Visual Basic .NET 裡，建構子被命名為 `New`，是個 `Sub`。
* Python 裡建構子的被分為 `__new__` 和 `__init__` 兩個方法。`__new__` 方法負責為實例分配內儲存空間，並接受自身的類作為參數（一般命名為 `cls`）。`__init__` 方法接受被新建的實例作為參數（一般稱為 `self`）。
* Object Pascal 的建構式用關鍵字 `constructor` 標識，並且可以起任意名字（但一般來說會被起名為 `Create`）。
* Objective-C 的建構式分成兩個方法，`alloc` 和 `init`。`alloc` 方法分配記憶體，`init` 負責初始化。`new` 方法會呼叫 `alloc` 和 `init` 兩者。

## 記憶體機制

在 Java, C# 和 VB .NET 裏，建構子會在一種叫做堆積的特殊資料結構裏建立作為參照類型的實例。數值類型（例如 int, double 等等）則會建立在叫做堆疊的有序資料結構中。VB .NET and C# 會允許用 `new` 來建立值類型的實例。然而在這些語言中，即使使用這種方法建立的物件依然只會在堆疊上。

在 C++ 中，不用 new 建立的物件會儲存在堆疊上，使用 new 建立時則會在堆積上。它們必須分別使用解構函式或者 delete 操作才能被刪除。

## 語言細節

### Java

在 Java 裡，建構子和其他方法的主要差別在於：

* 建構子不具有任何顯性回傳型別。
* 建構子無法直接被「`new`」啟動。
* 建構子無法被標示為 _synchronized_, _final_, _abstract_, _native_, 或者 _static_。

Java 裡的建構子會按照以下順序完成下列工作：

1. 將類別變數初始到預設值。（byte, short, int, long, float, 和 double 變數會預設設為它們相應的 0 值，booleans 會被設為 false, chars 會被設為空字元 ('\u0000')，物件參照會被設為 null）
2. 參照父類別的建構子，如果沒有定義任何建構子。
3. 將實例變數初始化到指定值。
4. 執行建構子內的程式碼。

在 Java 中可以通過關鍵詞 `super` 存取父類別的建構子。

不接收任何參數的建構子被稱作「無參數建構子」。

### Visual Basic .NET

在 Visual Basic .NET 中，建構子以 "`New`" 為定義方法，並且必須是個 Sub。

### C#

#### C# 靜態建構子

在 C# 中，_靜態建構子_是用來初始化任何靜態資料。靜態建構式也稱為「類建構式」，由於類建構式在生成的 MSIL 裡名為「.cctor」，因此也被稱為「cctor」。

靜態建構式允許複雜的靜態變數初始化。

靜態建構式在該類第一次被存取時呼叫，任何使用該類的操作（無論是呼叫靜態函式、屬性還是存取靜態變數，還是構造類別的實例）都會引發靜態建構式的執行。靜態建構式是執行緒安全的，並且是單例的。當用在泛型類中時，靜態建構式對於泛型的每個實例化都呼叫一次。靜態變數也同樣如此。

### C++

C++ 的建構式以該類別的名稱為標識，且不須寫回傳值型別也無法回傳數值：

建構式的函式體執行是在各個成員構造完**之後**才開始，因此要想更改成員的建構方法需要使用成員初始化列表：

基底類別的方式與成員相同，是在初始化列表中寫基底類別名、接建構式參數列：

複製建構式接受同類物件的左值參照（一般為 const T &）、移動建構式接受右值參照（一般為 T&&）：

C++ 中，程式設計師若未對某類別定義建構式（以及賦值函式、解構函式），編譯器在滿足條件時會定義相應的函式，參見 等頁面。

### F#

### Eiffel

### CFML

### Object Pascal

### Perl

### Perl with Moose

### PHP

### Python

### Ruby

## 注釋

## 參見

* 預設建構式
* 複製建構子

## 參考來源