構造函數

一種特殊的方法

構造函數,是一種特殊的方法。主要用來在創建對象時初始化對象,即為對象成員變數賦初始值,總與new運算符一起使用在創建對象的語句中。特別的一個類可以有多個構造函數,可根據其參數個數的不同或參數類型的不同來區分它們 即構造函數的重載。

主要特點


1.構造函數的命名必須和類名完全相同。在java中普通函數可以和構造函數同名,但是必須帶有返回值;
2.構造函數的功能主要用於在類的對象創建時定義初始化的狀態。它沒有返回值,也不能用void來修飾。這就保證了它不僅什麼也不用自動返回,而且根本不能有任何選擇。而其他方法都有返回值,即使是void返回值。儘管方法體本身不會自動返回什麼,但仍然可以讓它返回一些東西,而這些東西可能是不安全的;
3.構造函數不能被直接調用,必須通過new運算符在創建對象時才會自動調用;而一般的方法是在程序執行到它的時候被調用的;
4.當定義一個類的時候,通常情況下都會顯示該類的構造函數,並在函數中指定初始化的工作也可省略,不過Java編譯器會提供一個默認的構造函數。此默認構造函數是不帶參數的。而一般的方法不存在這一特點;
5.構造函數有回滾的效果,構造函數拋出異常時,構造的是一個不完整對象,會回滾,將此不完整對象的成員釋放(c++)
6.當一個類只定義了私有的構造函數,將無法通過new關鍵字來創建其對象,當一個類沒有定義任何構造函數,C#編譯器會為其自動生成一個默認的無參的構造函數。
7.在Python中構造函數必須通過重寫__init__方法實現

應用


C++構造函數
C++語言為類提供的構造函數可自動完成對象的初始化任務,全局對象和靜態對象的構造函數在main()函數執行之前就被調用,局部靜態對象的構造函數是當程序第一次執行到相應語句時才被調用。然而給出一個外部對象的引用性聲明時,並不調用相應的構造函數,因為這個外部對象只是引用在其他地方聲明的對象,並沒有真正地創建一個對象。
C++的構造函數定義格式為:
class <類名>
{
public:
<類名>(參數表);
//...(還可以聲明其它成員函數)
};
<類名>::<函數名>(參數表)
{
//函數體
}
如以下定義是合法的:
class T
{
public:
T(int a=0){ i=a; }//構造函數允許直接寫在類定義內,也允許有參數表。
int i;
};
如果一個類中沒有定義任何的構造函數,那麼編譯器只有在以下三種情況,才會提供默認的構造函數:
1、如果類有虛擬成員函數或者虛擬繼承父類(即有虛擬基類)時;
2、如果類的基類有構造函數(可以是用戶定義的構造函數,或編譯器提供的默認構造函數);
3、在類中的所有非靜態的對象數據成員,它們對應的類中有構造函數(可以是用戶定義的構造函數,或編譯器提供的默認構造函數)。
<類名>::<類名>(){},即不執行任何操作。
例子
#include using namespace std;class time{public: time()//constructor.構造函數 { hour=0; minute=0; sec=0; } void set_time(); void show_time();private: int hour, minute, sec;};int main(){ class time t1; t1.show_time(); t1.set_time(); t1.show_time(); return 0;}void time::set_time(){ cin>>hour>>minute>>sec;}void time::show_time(){ cout<
程序運行情況:
0:0:0
10 11 11 回車
10:11:11
任何時候,只要創建類或結構,就會調用它的構造函數。類或結構可能有多個接受不同參數的構造函數。構造函數使得程序員可設置默認值、限制實例化以及編寫靈活且便於閱讀的代碼。
PHP的構造函數
void__construct( [mixed args [, ...]] )
php 5 允行開發者在一個類中定義一個方法作為構造函數。具有構造函數的類會在每次創建對象時先調用此方法,所以非常適合在使用對象之前做一些初始化工作。
注:如果子類中定義了構造函數則不會暗中調用其父類的構造函數。要執行父類的構造函數,需要在子類的構造函數中調用parent::__construct()。
例子 使用新標準的構造函數
為了實現向後兼容性,如果 php 5 在類中找不到__construct()函數,它就會嘗試尋找舊式的構造函數,也就是和類同名的函數。因此唯一會產生兼容性問題的情況是:類中已有一個名為__construct()的方法,但它卻又不是構造函數。
Python的構造函數
定義格式為
class <類名>:
__init__(self [,參數表]):
#函數體
#其它的方法和屬性

其他特點


1.它的函數名與類名相同;
2.它可以重載;
3.不能指定返回類型,即使是void也不行;
4.雖然在一般情況下,構造函數不被顯式調用,而是在創建對象時自動被調用。但是並不是不能被顯式調用。有些時候是一定要顯式調用的,只要是父類有帶參的構造函數,在子類中就必須顯式的調用父類的構造函數,因為子類的構造器在實例化時無法找到父類的構造函數(當父類有自己寫的無參構造函數時,子類也不用顯式調用)。
void__destruct( void )
php 5 引入了析構函數的概念,這類似於其它面向對象的語言,如 C++。析構函數會在到某個對象的所有引。

語法


● 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” invokes them).
● 構造器無法被標示為synchronized, final, abstract, native, 或者static。
Java 里的構造器會按照以下順序完成下列工作:
● ● 將類變數初始到預設值。(byte, short, int, long, float, 和 double 變數會默認設為它們相應的0值,booleans 會被設為 false, chars 會被設為空字元('\u0000'),對象引用會被設為 null)
● ● 引用父類的構造器,如果沒有定義任何構造器。
● ● 將實例變數初始化到指定值。
● ● 執行構造器內的代碼。
在 Java 中可以通過關鍵詞super訪問父類的構造器。
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 constructorExample e = new Example(42);
不接收任何參數的構造器被稱作“無參數構造器”。
在Visual Basic .NET中, 構造函數以"New"為定義方法,並且必須是個 Sub。
Class Foobar Private strData As String ' Constructor Public Sub New(ByVal someParam As String) strData = someParam End SubEnd Class
' code somewhere else' instantiating an object with the above constructorDim foo As New Foobar(".NET")
C#
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 aboveMyClass c = new MyClass(42, "string");
C# 靜態構造函數
在C#中,靜態構造函數是用來初始化任何靜態數據。靜態構造函數也稱為“類構造函數”,由於類構造函數在生成的 MSIL 里名為“.cctor”,因此也被稱為“cctor”。
靜態構造函數允許複雜的靜態變數初始化。
靜態構造函數在該類第一次被訪問時調用,任何使用該類的操作(無論是調用靜態函數、屬性還是訪問靜態變數,還是構造類的實例)都會引發靜態構造函數的執行。靜態構造函數是線程安全的,並且是單例的。當用在泛型類中時,靜態構造函數對於泛型的每個實例化都調用一次。靜態變數也同樣如此。
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 32MyClass c = new MyClass();
C++
C++ 的構造函數以該類的類名為標識,且不寫返回值類型也無法返回值:
class C{public: C(void){ ... }};
構造函數的函數體執行是在各個成員構造完之後才開始,因此要想更改成員的構造方式需要使用成員初始化列表:
class D: public B{public: D(void): B("Hello, world!"){ ... }};
複製構造函數接受同類對象的左值引用(一般為 const T &)、移動構造函數接受右值引用(一般為 T&&):
class E{public: E(const E &e){...}//Copy constructor E(E &&e){...}//Move constructor};
C++ 中,程序員若未對某類定義構造函數(以及賦值函數、析構函數),編譯器在滿足條件時會定義相應的函數。
Ruby
irb(main):001:0> class ExampleClassirb(main):002:1> def initializeirb(main):003:2> puts "Hello there"irb(main):004:2> endirb(main):005:1> end=> nilirb(main):006:0> ExampleClass.newHello there=> #
  • 目錄