C++ -繼承與解構子的問題

C++ 的繼承與解構子的問題 (inheritance and destructor in C++)

範例繼承結構如下,有一個車子類別,卡車類別 繼承 車子類別。其中的 Run 函式是虛擬函式,用來實作多型。

車子類別

class CCar
{
public:
	CCar();
	~CCar();
	virtual void Run();
};

CCar::CCar()
{
	cout << "Car Constructor." << endl;
}
CCar::~CCar()
{
	cout << "Car Destructor." << endl;
}
void CCar::Run()
{
	cout << "Car Run." << endl;
}

卡車類別

class CCarTruck : public CCar
{
public:
	CCarTruck();
	~CCarTruck();
	virtual void Run();
};

CCarTruck::CCarTruck() :CCar()
{
	cout << "Truck Constructor." << endl;
}
CCarTruck::~CCarTruck()
{
	cout << "Truck Destructor." << endl;
}
void CCarTruck::Run()
{
	cout << "Truck Run." << endl;
}

主程式

#include <iostream>
#include "car.h"
using namespace std;

int main()
{
	cout << "CAR----------------------" << endl;
	CCar* pCar = new CCar;
	pCar->Run();
	delete pCar;

	cout << endl;

	cout << "TRUCK----------------------" << endl;
	CCarTruck* pTruck = new CCarTruck;
	pTruck->Run();
	delete pTruck;

	system("pause");
	return 0;
}
CAR———————-
Car Constructor.
Car Run.
Car Destructor.

TRUCK———————-
Car Constructor.
Truck Constructor.
Truck Run.
Truck Destructor.
Car Destructor.

恩,沒有什麼問題,子類別的 constructor 會先執行父類別的 constructor。子類別的 destructor 會先執行自己的 destructor 再執行父類別的 destructor。順序是正確的。

但是我們稍微改一下程式碼,試試看把 Run 和 delete 包進函式裡。

主程式

#include <iostream>
#include "car.h"
using namespace std;

void CarRun(CCar* pCar)
{
	pCar->Run();
	delete pCar;
}

int main()
{
	cout << "CAR----------------------" << endl;
	CCar* pCar = new CCar;
	CarRun(pCar);

	cout << endl;

	cout << "TRUCK----------------------" << endl;
	CCarTruck* pTruck = new CCarTruck;
	CarRun(pTruck);

	system("pause");
	return 0;
}
CAR———————-
Car Constructor.
Car Run.
Car Destructor.

TRUCK———————-
Car Constructor.
Truck Constructor.
Truck Run.
Car Destructor.

咦~ Truck Destructor.不見了,也就是說子類別的 destructor 沒有執行,為什麼呢?

這是因為 CarRun 函式的參數是 CCar * 啊,所以 delete 時當然呼叫是 CCar 的 destructor 囉!

但是子類別可以轉成父類別存在不是多型正常的用法嗎?而且怎麼 Run 函式就可以執行到子類別的啊?

因為 Run 函式是 virtual 的啊!所以這問題要怎麼解決呢?那就把 destructor 改成 virtual 囉!

修改類別宣告

class CCar
{
public:
	CCar();
	virtual ~CCar();	//改成 virtual
	virtual void Run();
};

class CCarTruck : public CCar
{
public:
	CCarTruck();
	virtual ~CCarTruck();	//改成 virtual
	virtual void Run();
};
CAR———————-
Car Constructor.
Car Run.
Car Destructor.

TRUCK———————-
Car Constructor.
Truck Constructor.
Truck Run.
Truck Destructor.
Car Destructor.

恩,正常了。

結論:基底類別的 destructor 最好宣告成 virtual,以避免多型下產生的 destructor 問題。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *