創建對象有以下四種形式:
#include <iostream>
using namespace std;
class A{
private:
int i;
public:
A(){ cout<<"調用沒有參數的構造函數"<<endl; }
A(int a):i(a){ cout<<"調用有一個參數的構造函數"<<endl; }
~A(){cout<<"成員變量為:"<<i<<"\t調用析構函數"<<endl;}
};
void main(){
A a0; //形式一:直接聲明一個對象
A a1(1); //形式二:隱式調用A帶一個參數的構造函數
A a2 = A(2); //形式三:顯式調用A帶一個參數構造函數
A *p = new A(3); //形式四:動態分配
}形式一:實際上等同於 A a0 = A();調用不帶參數的構造函數進行對象的創建
形式二:實際上等同於 A a1 = A(1);調用帶一個參數的構造函數進行對象的創建
形式三:與形式二相同,這三種形式其實都是按照參數調用對應的構造函數在棧中創建對象,使用完畢后,系統自動回收對象內存,無需手動釋放。
形式四:在堆內存中動態開辟空間創建對象,需要手動釋放內存。
形式四:在堆內存中動態開辟空間創建對象,需要手動釋放內存。
還有一點需要注意“A a3();”編譯和運行都沒有問題,但是並沒有創建對象
運行結果:
由圖可以得出如下結果:
(1)創建對象需要調用對應的構造函數,釋放對象需要調用析構函數。因為形式一對應的構造函數沒有對對象進行初始化所以成員變量i出現隨機數“-858993460”.
(2)析構的順序與構造順序相反,上面代碼中構造順序是a0,a1,a2 ;析構順序是a2,a1,a0.
(3)在棧中創建的對象無需手動釋放,系統自動回收。在堆中創建的對象需要手動釋放。在運行結果中調用了4次構造函數,然而析構函數只執行了3次,沒有釋放指針p所指向的對象。在上面程序末尾加入代碼delete p;p=NULL;運行結果如下:
堆中的對象也被刪除了。
但需要注意的是delete p;只是釋放了內存空間,指針p仍然指向那塊空間,所以一定要將p指針置為NULL;
#include <iostream>
using namespace std;
class A{
private:
int i;
public:
A(){ cout<<"調用沒有參數的構造函數"<<endl; }
A(int a):i(a){ cout<<"調用有一個參數的構造函數"<<endl; }
~A(){cout<<"成員變量為:"<<i<<"\t調用析構函數"<<endl;}
};
void main(){
A a0; //方法一:直接聲明一個對象
A a1(1); //方法二:隱式調用A帶一個參數的構造函數
A a2 = A(2); //方法三:顯式調用A帶一個參數構造函數
A *p = new A(3); //方法四:動態分配
delete p;
cout<<"delete后指針p指向的空間:"<<p<<endl;
p=NULL;
}
運行結果如下:
還需要注意的一點是,delete不能釋放棧中的空間。我曾經犯過一個錯誤,錯誤代碼如下:
#include <iostream>
using namespace std;
class A{
private:
int i;
public:
A(){ cout<<"調用沒有參數的構造函數"<<endl; }
A(int a):i(a){ cout<<"調用有一個參數的構造函數"<<endl; }
~A(){cout<<"成員變量為:"<<i<<"\t調用析構函數"<<endl;}
};
void main(){
A a(1);
A *p1 = &a;
delete p1; //希望釋放棧中的對象
}編譯沒有問題,但運行出錯。
所以delete一定要和new成對出現,delete釋放的是動態開辟的內存。棧中的內存不需要咱們去釋放,系統自己會回收。
如果構造函數有默認參數,則可能出現不知道調用哪個構造函數的問題
#include <iostream>
using namespace std;
class A{
private:
int i;
public:
A(){cout<<"調用沒有參數的構造函數"<<endl;}
A(int a = 0):i(a){ cout<<"調用有一個參數的構造函數"<<endl; }
};
void main(){
A a0;
}編譯器不知道該調用哪一個構造函數,所以刪除其中一個構造函數即可。
