以下分析一下,聲明對象指針,調用構造、析構函數的多種情況,先定義以下的一個基類與派生類。
class CBase
{
public:
CBase()
{
cout << "CBase()" << endl;
}
~CBase()
{
cout << "~CBase()" << endl;
}
};
class CDerived : public CBase
{
public:
CDerived()
{
cout << "CDerived()" << endl;
}
~CDerived()
{
cout << "~CDerived()" << endl;
}
};
1、只是聲明一個對象指針,沒有定義,所以不會分配內存,也不會調用構造函數。如下所示:
CBase *CBase1 = NULL;
/*
輸出結果:
(NULL)
*/
2、聲明一個基類指針,分配一個派生類對象空間,構造與直接聲明派生類一樣,析構的話只調用基類的析構函數,而不會調用派生類的析構函數。因為基類的析構函數未聲明為虛函數。如下所示:
CBase *pCBase = new CDerived();
delete pCBase;
/*
輸出結果:
CBase()
CDerived()
~CBase()
*/
3、在將CBase類的析構函數聲明為虛函數時,再執行上述代碼如下所示:
CBase *pCBase = new CDerived();
delete pCBase;
/*
輸出結果:
CBase()
CDerived()
~CDerived()
~CBase()
*/
所以基類的析構函數必須定義為虛函數,否則子類對象析構時,將無法調用子類的析構函數,造成內存泄露。
4、而聲明一個派生類指針,分配一個基類對象空間,會報錯,因為基類指針可以指向派生類對象而派生類指針不可以指向基類對象。如下所示:
CDerived *pCDerived = new CBase(); //error
delete pCDerived;
再看下面這個例子:
class CTest
{
public:
CTest():name("misaka") { } // 初始化列表
void sayHello() const
{
cout << "hello" << endl;
}
void showName() const
{
cout << name << endl;
}
private:
string name;
};
1、因為只聲明一個對象指針,而沒有分配內存空間,所以沒有給數據成員 name 分配內存,也不會調用構造函數,所以在試圖打印 name 時會崩潰。
CTest *PCTest = NULL;
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //error,造成程序崩潰
2、聲明一個對象指針並分配內存空間,就能調用構造函數,不再會崩潰。
CTest *PCTest = new CTest();
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //OK,打印出"misaka"
3、當然把 name 聲明為靜態變量也不會崩潰,因為在編譯前系統已經給靜態成員數據 name 分配了內存,如下所示:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
string CTest::name = "wangwu"; // 類外要初始化靜態變量
class CTest
{
public:
CTest(){ }
void sayHello() const
{
cout << "hello" << endl;
}
void showName() const
{
cout << name << endl;
}
private:
static string name;
};
int main()
{
CTest *PCTest = NULL;
PCTest->sayHello(); //打印出"hello"
PCTest->showName(); //OK,打印出"wangwu"
return 0;
}
/*
輸出結果:
hello
wangwu
*/