看書時發現,C++中的基類的構造函數不能為虛函數(VC6.0中為虛函數是不能通過編譯的),析構函數應該為虛函數(MFC中CObject的析構函數即為虛函數)。
通過以下面的代碼,來看看這樣的說法對不對:
測試一:
Java代碼
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived d; // 依次調用Base::Base(),Derived::Derived()
// 程序結束時依次調用Derived::~Derived(),Base::~Base()
return 0; // 注意現在基類的析構函數不是虛函數,但是按照調用順序不會造成內存洩露。
}
測試二:
Java代碼
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived *d2 = new Derived(); // 依次調用Base::Base(),Derived::Derived()
Base *pBase = d2;
delete pBase; // 只調用了Base::~Base(),而沒有調用Derived::~Derived()
// 因為這裡基類的析構函數不是虛函數
return 0;
}
測試三:
Java代碼
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" <<endl;
}
virtual ~Base()
{
cout << "Base::~Base()" <<endl;
}
};
class Derived : public Base
{
public:
Derived()
{
cout << "Derived::Derived()" <<endl;
}
~Derived()
{
cout << "Derived::~Derived()" <<endl;
}
};
int main(int argc, char* argv[])
{
Derived *d2 = new Derived(); // 依次調用Base::Base(),Derived::Derived()
Base *pBase = d2;
delete pBase; // 依次調用Derived::~Derived(),Base::~Base(),
// 因為這裡基類的析構函數是虛函數
return 0;
}
總結:
(1) 假如你不打算使用多態(用基類指針指向派生類實例),基類析構函數是否為虛函數是無關緊要的。
(2) 假如你打算使用多態,一定要注意了,讓基類的析構函數為虛函數。
PS: 對於非虛函數的調用,完全取決於指針的類型。因為非虛函數的地址在編譯階段就會根據指針的類型確定下來。舉一個簡單的例子,派生類有一個非虛函數f(),基類中不存在這樣的函數。使用一個基類指針指向一個派生類實例後,假如你打算使用這個基類指針調用f(),編譯器會讓你打消這個念頭(編譯無法通過)。
作者“icebergs”