繼承關系的構造函數和析構函數的執行順序為:
成都創新互聯公司是工信部頒發資質IDC服務器商,為用戶提供優質的成都電信服務器托管服務
1、父類構造函數執行。
2、子類構造函數執行。
3、子類析構函數執行。
4、父類析構函數執行。
組合關系的構造函數和析構函數執行順序為:
1、執行類成員對象的構造函數。
2、執行類自己的構造函數。
3、執行類自己的析構函數。
4、執行類成員的析構函數。
container有兩個成員,one,two,所以在執行這個container構造函數之前執行object類的構造函數兩次。
擴展資料:
把類的聲明放在main函數之前,它的作用域是全局的。這樣做可以使main函數更簡練一些。在main函數中定義了兩個對象并且給出了初值,然后輸出兩個學生的數據。
當主函數結束時調用析構函數,輸出stud has been destructe!。值得注意的是,真正實用的析構函數一般是不含有輸出信息的。
在本程序中,成員函數是在類中定義的,如果成員函數的數目很多以及函數的長度很長,類的聲明就會占很大的篇幅,不利于閱讀程序。
而且為了隱藏實現,一般是有必要將類的聲明和實現(具體方法代碼)分開編寫的,這也是一個良好的編程習慣。即可以在類的外面定義成員函數,而在類中只用函數的原型作聲明。
參考資料來源:百度百科-析構函數
構造函數只是起初始化值的作用,但實例化一個對象的時候,可以通過實例去傳遞參數,從主函數傳遞到其他的函數里面,這樣就使其他的函數里面有值了。
析構函數與構造函數的作用相反,用于撤銷對象的一些特殊任務處理,可以是釋放對象分配的內存空間。
把類的聲明放在main函數之前,它的作用域是全局的。這樣做可以使main函數更簡練一些。在main函數中定義了兩個對象并且給出了初值,然后輸出兩個學生的數據。
當主函數結束時調用析構函數,輸出stud has been destructe!。值得注意的是,真正實用的析構函數一般是不含有輸出信息的。
擴展資料:
當定義一個類的時候,通常情況下都會顯示該類的構造函數,并在函數中指定初始化的工作也可省略,不過Java編譯器會提供一個默認的構造函數.此默認構造函數是不帶參數的。而一般的方法不存在這一特點。
構造函數有回滾的效果,構造函數拋出異常時,構造的是一個不完整對象,會回滾,將此不完整對象的成員釋放(c++)。
當一個類只定義了私有的構造函數,將無法通過new關鍵字來創建其對象,當一個類沒有定義任何構造函數,C#編譯器會為其自動生成一個默認的無參的構造函數。
構造函數是一種用于創建對象的特殊函數,當創建對象是,系統自動調用構造函數,不能在程序中直接調用.
構造函數名與類名相同,一個類可以擁有多個構造函數(重載),構造函數可以有任意類型的參數,但不能具有返回類型!
構造函數的作用是:為對象分配空間;對數據成員賦初值;請求起他資源.
析構函數作用是清除對象,釋放內存等
類是編程人員表達自定義數據類型的C++機制。它和C語言中的結構類似,C++類
支持數據抽象和面向對象的程序設計,從某種意義上說,也就是數據類型的設
計和實現。
那么
String
類的原型如下
class
String
{
public:
String(const
char
*str=NULL);
//構造函數
String(const
String
other);
//拷貝構造函數
~String(void);
//析構函數
String
operator=(const
String
other);
//等號操作符重載,賦值函數
ShowString();
private:
char
*m_data;
//字符指針
};
String::~String()
{
delete
[]
m_data;
//析構函數,釋放地址空間
}
String::String(const
char
*str)
{
if
(str==NULL)//當初始化串不存在的時候,為m_data申請一個空間存放'/0';
{
m_data=new
char[1];
*m_data='/0';
}
else//當初始化串存在的時候,為m_data申請同樣大小的空間存放該串;
{
int
length=strlen(str);
m_data=new
char[length+1];
strcpy(m_data,str);
}
}
String::String(const
String
other)//拷貝構造函數,功能與構造函數類似。
{
int
length=strlen(other.m_data);
m_data=new
[length+1];
strcpy(m_data,other.m_data);
}
String
String::operator
=(const
String
other)
//賦值函數
{
if
(this==other)//當地址相同時,直接返回;
return
*this;
delete
[]
m_data;//當地址不相同時,刪除原來申請的空間,重新開始構造;
int
length=sizeof(other.m_data);
m_data=new
[length+1];
strcpy(m_data,other.m_data);
return
*this;
}
String::ShowString()//由于m_data是私有成員,對象只能通過public成員函數來訪問;
{
coutthis-m_dataendl;
}
測試一下:
main()
{
String
AD;
char
*
p="ABCDE";
String
B(p);
AD.ShowString();
AD=B;
AD.ShowString();
}
摘 要:構造函數與析構函數是一個類中看似較為簡單的兩類函數,但在實際運用過程中總會出現一些意想不到的運行錯誤。本文將較系統的介紹構造函數與析構函數的原理及在C#中的運用,以及在使用過程中需要注意的若干事項。
關鍵字:構造函數;析構函數;垃圾回收器;非托管資源;托管資源
一.構造函數與析構函數的原理
作為比C更先進的語言,C#提供了更好的機制來增強程序的安全性。C#編譯器具有嚴格的類型安全檢查功能,它幾乎能找出程序中所有的語法問題,這的確幫了程序員的大忙。但是程序通過了編譯檢查并不表示錯誤已經不存在了,在“錯誤”的大家庭里,“語法錯誤”的地位只能算是冰山一角。級別高的錯誤通常隱藏得很深,不容易發現。
根據經驗,不少難以察覺的程序錯誤是由于變量沒有被正確初始化或清除造成的,而初始化和清除工作很容易被人遺忘。微軟利用面向對象的概念在設計C#語言時充分考慮了這個問題并很好地予以解決:把對象的初始化工作放在構造函數中,把清除工作放在析構函數中。當對象被創建時,構造函數被自動執行。當對象消亡時,析構函數被自動執行。這樣就不用擔心忘記對象的初始化和清除工作。
二.構造函數在C#中的運用
構造函數的名字不能隨便起,必須讓編譯器認得出才可以被自動執行。它的命名方法既簡單又合理:讓構造函數與類同名。除了名字外,構造函數的另一個特別之處是沒有返回值類型,這與返回值類型為void的函數不同。如果它有返回值類型,那么編譯器將不知所措。在你可以訪問一個類的方法、屬性或任何其它東西之前, 第一條執行的語句是包含有相應類的構造函數。甚至你自己不寫一個構造函數,也會有一個缺省構造函數提供給你。
class TestClass
{
public TestClass(): base() {} // 由CLR提供
}
下面列舉了幾種類型的構造函數
1)缺省構造函數
class TestClass
{
public TestClass(): base() {}
}
上面已介紹,它由系統(CLR)提供。
2)實例構造函數
實例構造函數是實現對類中實例進行初始化的方法成員。如:
using System;
class Point
{
public double x, y;
public Point()
{
this.x = 0;
this.y = 0;
}
public Point(double x, double y)
{
this.x = x;
this.y = y;
}
}
class Test
{
static void Main()
{
Point a = new Point();
Point b = new Point(3, 4); // 用構造函數初始化對象
}
}
聲明了一個類Point,它提供了兩個構造函數。它們是重載的。一個是沒有參數的Point構造函數和一個是有兩個double參數的Point構造函數。如果類中沒有提供這些構造函數,那么會CLR會自動提供一個缺省構造函數的。但一旦類中提供了自定義的構造函數,如Point()和Point(double x, double y),則缺省構造函數將不會被提供,這一點要注意。
3) 靜態構造函數
靜態構造函數是實現對一個類進行初始化的方法成員。它一般用于對靜態數據的初始化。靜態構造函數不能有參數,不能有修飾符而且不能被調用,當類被加載時,類的靜態構造函數自動被調用。如:
using System.Data;
class Employee
{
private static DataSet ds;
static Employee()
{
ds = new DataSet(...);
}
}
聲明了一個有靜態構造函數的類Employee。注意靜態構造函數只能對靜態數據成員進行初始化,而不能對非靜態數據成員進行初始化。但是,非靜態構造函數既可以對靜態數據成員賦值,也可以對非靜態數據成員進行初始化。
如果類僅包含靜態成員,你可以創建一個private的構造函數:private TestClass() {…},但是private意味著從類的外面不可能訪問該構造函數。所以,它不能被調用,且沒有對象可以被該類定義實例化。
以上是幾種類型構造函數的簡單運用,下面將重點介紹一下在類的層次結構中(即繼承結構中)基類和派生類的構造函數的使用方式。派生類對象的初始化由基類和派生類共同完成:基類的成員由基類的構造函數初始化,派生類的成員由派生類的構造函數初始化。
當創建派生類的對象時,系統將會調用基類的構造函數和派生類的構造函數,構 造函數的執行次序是:先執行基類的構造函數,再執行派生類的構造函數。如果派生類又有對象成員,則,先執行基類的構造函數,再執行成員對象類的構造函數,最后執行派生類的構造函數。
至于執行基類的什么構造函數,缺省情況下是執行基類的無參構造函數,如果要執行基類的有參構造函數,則必須在派生類構造函數的成員初始化表中指出。如:
class A
{ private int x;
public A( ) { x = 0; }
public A( int i ) { x = i; }
};
class B : A
{ private int y;
public B( ) { y = 0; }
public B( int i ) { y = i; }
public B( int i, int j ):A(i) { y = j; }
};
B b1 = new B(); //執行基類A的構造函數A(),再執行派生類的構造函數B()
B b2 = new B(1); //執行基類A的構造函數A(),再執行派生類的構造函數B(int)
B b3 = new B(0,1); //執行執行基類A的構造函數A(int) ,再執行派生類的
構造函數B(int,int)
在這里構造函數的執行次序是一定要分析清楚的。另外,如果基類A中沒有提供無參構造函數public A( ) { x = 0; },則在派生類的所有構造函數成員初始化表中必須指出基類A的有參構造函數A(i),如下所示:
class A
{ private int x;
public A( int i ) { x = i; }
};
class B : A
{ private int y;
public B():A(i) { y = 0; }
public B(int i):A(i) { y = i; }
public B(int i, int j):A(i) { y = j; }
};
三.析構函數和垃圾回收器在C#中的運用
析構函數是實現銷毀一個類的實例的方法成員。析構函數不能有參數,不能任何修飾符而且不能被調用。由于析構函數的目的與構造函數的相反,就加前綴‘~’以示區別。
雖然C#(更確切的說是CLR)提供了一種新的內存管理機制---自動內存管理機制(Automatic memory management),資源的釋放是可以通過“垃圾回收器” 自動完成的,一般不需要用戶干預,但在有些特殊情況下還是需要用到析構函數的,如在C#中非托管資源的釋放。
資源的.釋放一般是通過"垃圾回收器"自動完成的,但具體來說,仍有些需要注意的地方:
1. 值類型和引用類型的引用其實是不需要什么"垃圾回收器"來釋放內存的,因為當它們出了作用域后會自動釋放所占內存,因為它們都保存在棧(Stack)中;
2. 只有引用類型的引用所指向的對象實例才保存在堆(Heap)中,而堆因為是一個自由存儲空間,所以它并沒有像"棧"那樣有生存期("棧"的元素彈出后就代表生存期結束,也就代表釋放了內存),并且要注意的是,"垃圾回收器"只對這塊區域起作用;
然而,有些情況下,當需要釋放非托管資源時,就必須通過寫代碼的方式來解決。通常是使用析構函數釋放非托管資源,將用戶自己編寫的釋放非托管資源的代碼段放在析構函數中即可。需要注意的是,如果一個類中沒有使用到非托管資源,那么一定不要定義析構函數,這是因為對象執行了析構函數,那么"垃圾回收器"在釋放托管資源之前要先調用析構函數,然后第二次才真正釋放托管資源,這樣一來,兩次刪除動作的花銷比一次大多的。下面使用一段代碼來示析構函數是如何使用的:
public class ResourceHolder
{
~ResourceHolder()
{
// 這里是清理非托管資源的用戶代碼段
}
}
四.小結
構造函數與析構函數雖然是一個類中形式上較簡單的函數,但它們的使用決非看上去那么簡單,因此靈活而正確的使用構造函數與析構函數能夠幫你更好的理解CLR的內存管理機制,以及更好的管理系統中的資源。