it-swarm.dev

Apa yang dapat menyebabkan panggilan fungsi virtual murni di C++?

Saya mengajar kelas pemrograman C++ dan saya telah melihat cukup kelas kesalahan sehingga saya memiliki perasaan yang baik untuk bagaimana mendiagnosis bug C++ umum. Namun, ada satu jenis kesalahan utama yang intuisi saya tidak terlalu baik: kesalahan pemrograman apa yang menyebabkan panggilan ke fungsi virtual murni? Kesalahan paling umum yang pernah saya lihat yang menyebabkan ini memanggil fungsi virtual dari konstruktor kelas dasar atau destruktor. Apakah ada orang lain yang harus saya ketahui ketika membantu men-debug kode siswa?

33
templatetypedef

"Kesalahan paling umum yang saya lihat yang menyebabkan ini memanggil fungsi virtual dari konstruktor atau destruktor kelas dasar."

Ketika sebuah objek dibangun, pointer ke tabel pengiriman virtual awalnya ditujukan pada superclass tertinggi, dan itu hanya diperbarui sebagai kelas menengah yang menyelesaikan konstruksi. Jadi, Anda dapat secara tidak sengaja memanggil implementasi virtual murni hingga titik bahwa subclass - dengan implementasi fungsi overriding sendiri - menyelesaikan konstruksi. Itu mungkin subclass yang paling diturunkan, atau di mana saja di antaranya.

Ini mungkin terjadi jika Anda mengikuti pointer ke objek yang dikonstruksi sebagian (mis. Dalam kondisi balapan karena operasi async atau berulir).

Jika seorang kompiler memiliki alasan untuk berpikir ia mengetahui tipe nyata yang ditunjuk oleh pointer-to-base-class, ia mungkin mem-bypass pengiriman virtual. Anda mungkin bingung dengan melakukan sesuatu dengan perilaku yang tidak ditentukan seperti pemeran ulang.

Selama kehancuran, tabel pengiriman virtual harus dikembalikan sebagai kelas turunan dihancurkan, sehingga implementasi virtual murni dapat lagi dipanggil.

Setelah penghancuran, terus menggunakan objek melalui pointer "menggantung" atau referensi dapat memanggil fungsi virtual murni, tetapi tidak ada perilaku yang pasti dalam situasi seperti itu.

28
Tony Delroy

Berikut adalah beberapa kasus di mana panggilan virtual murni dapat terjadi.

  1. Menggunakan pointer menggantung - pointer bukan dari objek yang valid sehingga tabel virtual yang ditunjuknya hanyalah memori acak yang mungkin berisi NULL
  2. Bad cast menggunakan static_cast ke tipe yang salah (atau cast gaya-C) juga dapat menyebabkan objek yang Anda tuju tidak memiliki metode yang benar dalam tabel virtualnya (dalam hal ini setidaknya itu benar-benar adalah tabel virtual tidak seperti opsi sebelumnya).
  3. DLL telah diturunkan - Jika objek yang Anda pegang dibuat dalam file objek bersama (DLL, jadi, sl) yang telah diturunkan lagi, memori dapat di-nolkan sekarang
8
Motti

Ini bisa terjadi misalnya ketika referensi atau penunjuk ke objek menunjuk ke lokasi NULL, dan Anda menggunakan referensi objek atau penunjuk untuk memanggil fungsi virtual di kelas. Sebagai contoh: 

std::vector <DerivedClass> objContainer;  
if (!objContainer.empty()) 
   const BaseClass& objRef = objContainer.front();  
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());   
const std::string& name = objRef.name();  
// -> (name() is a pure virtual function in base class, 
// which has been implemented in DerivedClass).

Pada titik ini objek yang disimpan di objContainer [0] tidak ada. Ketika tabel virtual diindeks, tidak ditemukan lokasi memori yang valid. Oleh karena itu, galat run time dikeluarkan yang mengatakan "fungsi virtual murni disebut". 

0
cppcoder