Ini bahkan lebih penting untuk antarmuka. Setiap pengguna kelas Anda mungkin akan memegang pointer ke antarmuka, bukan pointer ke implementasi konkret. Ketika mereka datang untuk menghapusnya, jika destructor non-virtual, mereka akan memanggil destructor antarmuka (atau default yang disediakan compiler, jika Anda tidak menentukan satu), bukan destructor kelas turunan. Kebocoran memori instan.
Sebagai contoh
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
delete p
memohon perilaku yang tidak terdefinisi. Tidak dijamin untuk meneleponInterface::~Interface
.[expr.delete]/
:... if the static type of the object to be deleted is different from its dynamic type, ... the static type shall have a virtual destructor or the behavior is undefined. ...
. Masih akan tidak terdefinisi jika Turun menggunakan destruktor yang dihasilkan secara implisit.Jawaban atas pertanyaan Anda sering, tetapi tidak selalu. Jika kelas abstrak Anda melarang klien untuk memanggil delete pada pointer ke sana (atau jika dikatakan demikian dalam dokumentasinya), Anda bebas untuk tidak mendeklarasikan destruktor virtual.
Anda dapat melarang klien untuk memanggil delete pada sebuah pointer ke sana dengan membuat destruktornya terlindungi. Bekerja seperti ini, sangat aman dan masuk akal untuk menghilangkan destruktor virtual.
Anda pada akhirnya akan berakhir dengan tidak ada tabel metode virtual, dan akhirnya menandakan klien Anda niat Anda untuk membuatnya tidak dapat dihapus melalui pointer ke sana, jadi Anda memang punya alasan untuk tidak menyatakannya virtual dalam kasus-kasus tersebut.
[Lihat item 4 dalam artikel ini: http://www.gotw.ca/publications/mill18.htm ]
sumber
Saya memutuskan untuk melakukan riset dan mencoba merangkum jawaban Anda. Pertanyaan-pertanyaan berikut akan membantu Anda memutuskan jenis destruktor apa yang Anda butuhkan:
Saya harap ini membantu.
* Penting untuk dicatat bahwa tidak ada cara di C ++ untuk menandai kelas sebagai final (yaitu non subclassable), jadi jika Anda memutuskan untuk mendeklarasikan destruktor Anda non-virtual dan publik, ingatlah untuk secara eksplisit memperingatkan sesama programmer terhadap berasal dari kelas Anda.
Referensi:
sumber
Ya itu selalu penting. Kelas turunan dapat mengalokasikan memori atau menyimpan referensi ke sumber daya lain yang perlu dibersihkan ketika objek dihancurkan. Jika Anda tidak memberikan antarmuka / kelas abstrak destruktor virtual Anda, maka setiap kali Anda menghapus turunan kelas turunan melalui kelas dasar menangani destruktor kelas turunan Anda tidak akan dipanggil.
Karenanya, Anda membuka potensi kebocoran memori
sumber
Itu tidak selalu diperlukan, tetapi saya menemukan itu sebagai praktik yang baik. Apa yang dilakukannya, adalah memungkinkan objek yang diturunkan dihapus dengan aman melalui pointer dari tipe dasar.
Jadi misalnya:
terbentuk dengan buruk jika
Base
tidak memiliki destruktor virtual, karena ia akan berusaha untuk menghapus objek seolah-olah itu adalahBase *
.sumber
shared_ptr
akan mencoba untuk menghapus objek seolah-olah ituBase *
- ia mengingat jenis benda yang Anda buat dengannya. Lihat tautan yang direferensikan, khususnya bit yang mengatakan "Destructor akan memanggil delete dengan pointer yang sama, lengkap dengan tipe aslinya, bahkan ketika T tidak memiliki destruktor virtual, atau batal."Ini bukan hanya latihan yang bagus. Ini adalah aturan # 1 untuk hierarki kelas apa pun.
Sekarang untuk Mengapa. Ambil hierarki hewan yang khas. Destructor virtual melalui pengiriman virtual seperti halnya metode lain memanggil. Ambil contoh berikut.
Asumsikan bahwa Hewan adalah kelas abstrak. Satu-satunya cara C ++ mengetahui destructor yang tepat untuk dipanggil adalah melalui metode pengiriman virtual. Jika destruktor itu bukan virtual maka ia hanya akan memanggil destruktor Animal dan tidak menghancurkan objek apa pun di kelas turunan.
Alasan untuk membuat virtual destruktor di kelas dasar adalah karena ia hanya menghilangkan pilihan dari kelas turunan. Destructor mereka menjadi virtual secara default.
sumber
Jawabannya sederhana, Anda harus virtual jika tidak, kelas dasar tidak akan menjadi kelas polimorfik lengkap.
Anda lebih suka penghapusan di atas, tetapi jika destructor kelas dasar bukan virtual, hanya destruktor kelas dasar akan dipanggil dan semua data dalam kelas turunan akan tetap terhapus.
sumber