作者littleshan (我要加入劍道社!)
看板C_and_CPP
標題Re: [問題] pure virtual destructor 怎宣告?
時間Tue May 18 15:57:30 2010
※ 引述《QQ29 (我愛阿蓉)》之銘言:
: 有其他class會繼承A
: 其實我code中 class是寫interface 其實就是struct
: 但他的destructor不給我宣告成pure
: 他一定要我定義
: 所以一定要改成 virtual ~A(){}...
: 不然就是 外頭在 定義一次A::~A(){}
: 但我覺得很沒道理 interface不就是包一堆pure virtual function 給別人繼承後
: override嗎?
: 還是其實在外面寫個空的destructor{} 其實也沒差
: 如果使用者寫 A* p =new A;
: 因為virtual ~A()=0 他也會compile error說 abstract class不給你產生instance
: 所以其實我在外面寫A::~A(){} 是正確的做法沒有關係???
: 不太懂 正統的作法該怎麼寫耶
: 謝謝
又到了講觀念的時候~
Destructor 和 member function 有極大的不同,首先,你並不會「主動」呼叫
dtor,它總是由 compiler 在物件脫離它的 scope 時,或是使用者呼叫 delete 時,
由 compiler 自動幫你呼叫的。(儘管你可以手動呼叫 dtor,但請不要做這種事,
問題會出乎你意料地多)
dtor 負責終結一個物件、送回它所占用的資源。只要 class 有定義 dtor,那麼它
一定要在物件生命結束時被呼叫,否則會產生各式各樣的資源洩露。
試想一下你寫了這樣一個 class:
class Base {
public:
Base(size_t n) : my_data(new int[n])
{}
~Base()
{
delete [] my_data;
}
private:
int* my_data;
};
這個 class 的意圖很明顯:它在 ctor 中配置了記憶體,同時在 dtor 中釋放,
只要使用者遵守 C++ 的規則 (有 new 就有 delete),基本上可以運作無誤。
(其實我還需要處理一下 copy-ctor 及 copy-assignment,但這不是本文重點)
現在想像一下,如果你有一個 Derived class 要繼承 Base,那你應該怎麼寫
Derived dtor 呢?
class Derived : public Base {
public:
Derived(size_t n)
: Base(n), my_derived_data(new char[n])
{}
~Derived()
{
// 這邊要怎麼寫?
}
private:
char* my_derived_data;
};
我們來看幾件一定要知道的事:
* 首先,你一定要寫 ~Derived()。因為 Derived 有可能有自己的成員 (在此例
中即為 my_derived_data),而 Base 對 Derived 一無所知,所以你不可能在
Base 中去幫 Derived 釋放 my_derived_data。
* 再來,你在 ~Derived() 中,唯一能做的就是釋放 Derived 自己的成員。因為
Base::my_data 被宣告為 private,你不可能動到它。而且若由 Derived class
負責釋放 Base class 的成員,將導致程式難以維護。想像一下你如果在 Base
中增加了一個成員,難道要去檢查並修改所有繼承它的 class 嗎?這會是天大
災難。
* 所以你可能會這樣寫:
Derived::~Derived()
{
delete [] my_derived_data;
~Base(); // 呼叫 Base dtor 以釋放 Base::my_data
}
這樣就解決了上面說的兩個問題,只要 ~Base() 有好好清理他自己的 member,
那麼在 ~Derived() 中,清理完自己的 member 後呼叫 ~Base() 即可順利清理
整個物件。
不過你會發現,只要你繼承了某個物件,你一定要在 dtor 中呼叫爸爸的 dtor,
才能確保爸爸的遺產(?)都有被正確清理掉。這件事是重覆性的工作,而且很容
易被 programmer 忘掉。所以 C++ compiler 幫你做了一件事:
Compiler 會自動在所有 dtor 的結尾處,加入對 base class dtor 的呼叫。
(當然,如果這個 class 沒繼承,就不會做這件事了。)
所以你的 ~Derived 只需要一行:
Derived::~Derived()
{
delete my_derived_data;
// compiler 會在這自動呼叫 ~Base() 以清理爸爸的遺產
}
寫到這邊,你應該知道為什麼 base class dtor 不可以是 pure-virtual 了。
如果它是 pure-virtual,表示 compiler 在 ~Derived() 中插入對 ~Base() 的呼叫,
將會變成非法動作。
回到你的例子:
class A
{
public:
........一些pure virtual function
virtual ~A() {};
};
~A() 就放個空定義即可。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.112.29.108
推 VictorTom:推~~~~~~~~~~~~ 05/18 16:24
→ tinlans:還是可以宣告成 pure,用來表示那個 class 是 abstract。 05/18 16:46
→ tinlans:只是定義還是得提供一份就是了。 05/18 16:46
→ tinlans:要造 polymorphic class 又找不到 method 可以放 virtual 05/18 16:46
→ tinlans:,一般都是拿 destructor 來開刀。由 pure / non-pure 05/18 16:47
→ tinlans:來決定這個 class 能不能有 instance。 05/18 16:47
推 QQ29:謝謝l大 勞煩您 這麼一大篇 = = thx 05/18 17:16
→ littleshan:啊,感謝二樓補充,我看過的code不多所以很少見到這種 05/18 17:30
推 loveme00835:推一個~ 05/18 17:55
推 QQ29:l大你竟然說看得不多...卻有如此造詣...太誇張了.... 05/18 17:59
→ loveme00835:剛好發現Effective C++ Item 14 剛好也有講這件事 05/18 18:46
推 lwecloud:推~侯捷的書也會特別去提這點 05/18 19:52
推 netio:那如果Derived沒call Base的ctor不就... 05/18 20:06
推 holymars:給樓上的 那不就會call default ctor嗎.. 05/18 20:07
→ holymars:如果沒有default ctor可以call,根本就不會過XD 05/18 20:08
→ netio:剛試了把Base(n)拿掉確實不給過XD 05/18 20:32
推 tomap41017:感謝一大篇辛苦了!!!!!!!!!!! 05/18 22:44