Kapan static_cast, dynamic_cast, const_cast, dan reinterpret_cast digunakan?

Apa penggunaan yang tepat:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • Nilai C-style (type)value
  • type(value) gaya casting

Bagaimana Anda memutuskan apa yang akan digunakan dalam kasus apa?

2153
01 дек. ditetapkan oleh e.James 01 Des. 2008-12-01 23:11 '08 pukul 11:11 malam 2008-12-01 23:11
@ 8 jawaban

static_cast adalah pemeran pertama yang harus Anda coba gunakan. Itu melakukan hal-hal seperti konversi implisit antara jenis (misalnya, dari int ke float atau pointer ke void* ), dan itu juga dapat memanggil fungsi konversi eksplisit (atau yang implisit). Dalam banyak kasus, static_cast tidak secara eksplisit dinyatakan, tetapi penting untuk dicatat bahwa sintaks T(something) setara dengan (T)something , dan harus dihindari (lebih lanjut tentang ini nanti). T(something, something_else) aman dan, bagaimanapun, dijamin untuk memanggil konstruktor.

static_cast juga dapat dilakukan melalui hierarki warisan. Ini tidak perlu ketika melempar ke atas (menuju kelas dasar), tetapi ketika menjatuhkannya dapat digunakan sampai mewarisi warisan virtual . Namun, validasi tidak dilakukan, dan perilaku yang tidak terdefinisi dengan static_cast ke bawah hierarki adalah tipe yang bukan tipe objek.


const_cast dapat digunakan untuk menghapus atau menambahkan const ke variabel; tidak ada metode C ++ lain yang dapat menghapusnya (bahkan tidak reinterpret_cast ). Penting untuk dicatat bahwa perubahan nilai const sebelumnya hanya tidak terdefinisi jika variabel const awal; jika Anda menggunakannya untuk menghapus tautan const ke sesuatu yang tidak dideklarasikan menggunakan const , itu aman. Ini dapat bermanfaat, misalnya, ketika melakukan overloading fungsi anggota berdasarkan const . Itu juga dapat digunakan untuk menambahkan const ke objek, misalnya, untuk memanggil kelebihan fungsi anggota.

const_cast juga berfungsi mirip dengan volatile , meskipun ini kurang umum.


dynamic_cast digunakan hampir secara eksklusif untuk memproses polimorfisme. Anda bisa overlay pointer atau tautan ke tipe polimorfik apa pun pada tipe kelas lainnya (tipe polimorfik memiliki setidaknya satu fungsi virtual yang dideklarasikan atau diwarisi). Anda dapat menggunakannya lebih dari sekadar melemparkannya - Anda dapat membuangnya ke samping atau bahkan rantai lainnya. dynamic_cast akan mencari objek yang diinginkan dan, jika memungkinkan, mengembalikannya. Jika tidak bisa, itu akan mengembalikan nullptr dalam kasus pointer, atau membuang std::bad_cast dalam kasus tautan.

dynamic_cast memiliki beberapa batasan. Ini tidak berfungsi jika ada beberapa objek dengan tipe yang sama dalam hierarki warisan (yang disebut "berlian menakutkan"), dan Anda tidak menggunakan warisan virtual . Itu juga dapat melewati hanya melalui warisan publik - itu akan selalu membawa protected atau private melalui warisan. Ini jarang masalah, karena bentuk-bentuk warisan seperti itu jarang terjadi.


reinterpret_cast adalah lemparan paling berbahaya dan harus digunakan sangat hemat. Ini mengubah satu jenis >int atau segala macam hal tidak menyenangkan lainnya. Pada dasarnya, satu-satunya jaminan yang Anda dapatkan dengan reinterpret_cast adalah bahwa biasanya, jika Anda mengembalikan hasilnya ke tipe aslinya, Anda akan mendapatkan nilai yang sama (tetapi tidak jika tipe perantara lebih kecil dari tipe aslinya). Ada sejumlah transformasi yang tidak dapat dilakukan reinterpret_cast . Itu digunakan terutama untuk transformasi aneh dan manipulasi dengan bit, seperti mengubah aliran data mentah menjadi data aktual atau menyimpan data dalam bit yang lebih rendah dari pointer yang disejajarkan.


Daftar gaya <style>> adalah masing-masing type(object) (type)object atau type(object) . Daftar gaya-C didefinisikan sebagai yang pertama dari yang berikut, yang berhasil:

  • const_cast
  • static_cast (meskipun mengabaikan batasan akses)
  • static_cast (lihat di atas), lalu const_cast
  • reinterpret_cast
  • reinterpret_cast , lalu const_cast

Dalam beberapa kasus, ini dapat digunakan sebagai pengganti hantu lain, tetapi bisa sangat berbahaya karena kemampuan untuk masuk ke reinterpret_cast , dan yang terakhir harus lebih disukai ketika casting eksplisit diperlukan jika Anda tidak yakin static_cast akan berhasil atau reinterpret_cast akan berakhir dengan karena kesalahan. Itupun mempertimbangkan opsi yang lebih panjang, lebih eksplisit.

Para static_cast gaya-C juga mengabaikan kontrol akses ketika menjalankan static_cast , yang berarti mereka memiliki kemampuan untuk melakukan operasi yang tidak dapat dilakukan oleh pemain lain. Ini terutama kludge, dan menurut saya, ini adalah alasan lain untuk menghindari pemeran C-style.

2286
01 дек. jawabannya diberikan coppro 01 desember . 2008-12-01 23:26 '08 pada 11:26 siang 2008-12-01 23:26

Gunakan dynamic_cast untuk mengonversi pointer / tautan ke hierarki warisan.

Gunakan static_cast untuk konversi jenis biasa.

Gunakan reinterpret_cast untuk reinterpretasi pola bit tingkat rendah. Gunakan dengan sangat hati-hati.

Gunakan const_cast untuk menjatuhkan const/volatile . Hindari ini jika Anda tidak terjebak menggunakan API yang salah.

298
01 дек. Jawaban diberikan oleh Fred Larson 01 Des. 2008-12-01 23:22 '08 pada 11:22 2008-12-01 23:22

(Banyak penjelasan teoretis dan konseptual diberikan di atas)

Di bawah ini adalah beberapa contoh praktis ketika saya menggunakan static_cast , dynamic_cast , const_cast , reinterpret_cast .

(Juga lihat ini untuk memahami penjelasan: http://www.cplusplus.com/doc/tutorial/typecasting/ )

static_cast:

 OnEventData(void* pData) { ...... // pData is a void* pData, // EventData is a structure eg // typedef struct _EventData { // std::string id; // std:: string remote_id; // } EventData; // On Some Situation a void pointer *pData // has been static_casted as // EventData* pointer EventData *evtdata = static_cast<EventData*>(pData); ..... } 

dynamic_cast:

 void DebugLog::OnMessage(Message *msg) { static DebugMsgData *debug; static XYZMsgData *xyz; if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){ // debug message } else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){ // xyz message } else{ // ... } } 

const_cast:

 // *Passwd declared as a const const unsigned char *Passwd // on some situation it require to remove its constness const_cast<unsigned char*>(Passwd) 

reinterpret_cast:

 typedef unsigned short uint16; // Read Bytes returns that 2 bytes got read. bool ByteBuffer::ReadUInt16(uint16 val) { return ReadBytes(reinterpret_cast<char*>( 2); } 
165
21 янв. jawabannya diberikan oleh Sumit Arora 21 Jan 2014-01-21 07:53 '14 pada 7:53 2014-01-21 07:53

Ini dapat membantu jika Anda tahu sedikit ...

static_cast

  • Kompiler C ++ sudah tahu cara mengonversi tipe penskalaan, seperti float, ke int. Gunakan static_cast untuk mereka.
  • Ketika Anda meminta kompiler untuk mengonversi tipe A ke B , static_cast memanggil konstruktor B meneruskan A sebagai parameter. Atau, A dapat memiliki operator transformasi (mis., A::operator B() ). Jika B tidak memiliki konstruktor atau A tidak memiliki operator transformasi, Anda akan mendapatkan kesalahan waktu kompilasi.
  • Konversi dari A* ke B* selalu berhasil jika A dan B berada dalam hierarki warisan (atau batal), jika tidak, Anda akan mendapatkan kesalahan kompilasi.
  • Koreksi : jika Anda melemparkan pointer basis ke pointer yang diturunkan, tetapi jika objek sebenarnya bukan tipe turunan, Anda tidak akan mendapatkan kesalahan. Anda mendapatkan pointer buruk dan kemungkinan besar segfault saat runtime. Hal yang sama berlaku untuk A> B> .
  • Got : para pemeran dari Derived to Base atau sebaliknya akan membuat salinan baru! Bagi orang-orang yang berasal dari C # / Java, ini bisa menjadi kejutan besar, karena hasilnya pada dasarnya adalah objek terputus yang dibuat dari Berasal.

dynamic_cast

  • dynamic_cast menggunakan informasi tipe runtime untuk menentukan apakah para pemain valid. Sebagai contoh, dari (Base*) ke (Derived*) dapat gagal jika pointer sebenarnya bukan tipe turunan.
  • Ini berarti bahwa dynamic_cast sangat mahal dibandingkan dengan static_cast!
  • Untuk A* ke B* , jika gips tidak benar, maka dynamic_cast akan mengembalikan nullptr.
  • Untuk A> ke B> jika para pemain tidak benar, maka dynamic_cast akan melempar pengecualian bad_cast.
  • Tidak seperti hantu lainnya, ada overhead runtime.

const_cast

  • Sementara static_cast dapat melakukan konstanta tidak konstan, ia tidak dapat mengikuti jalur yang berbeda. Const_cast dapat bekerja di kedua arah.
  • Salah satu contoh di mana ini nyaman adalah untuk beralih melalui wadah, misalnya, set<T> yang mengembalikan hanya elemen-elemennya sebagai const, untuk memastikan bahwa Anda belum mengubah kuncinya. Namun, jika niat Anda adalah mengubah anggota non-kunci dari objek, maka semuanya akan baik-baik saja. Anda dapat menggunakan const_cast untuk menghapus constness.
  • Contoh lain adalah ketika Anda ingin menerapkan T foo() serta const T foo() . Untuk menghindari duplikasi kode, Anda dapat menggunakan const_cast untuk mengembalikan nilai satu fungsi dari yang lain.

reinterpret_cast

  • Itu pada dasarnya mengatakan bahwa mengambil byte ini di lokasi memori ini dan menganggapnya sebagai objek yang diberikan.
  • Misalnya, Anda dapat memuat 4 byte dengan titik apung ke 4 byte dengan integer untuk melihat seperti apa bit-bit itu dalam titik mengambang.
  • Jelas, jika data tidak cocok dengan jenisnya, Anda bisa mendapatkan segfault.
  • Tidak ada overhead waktu untuk kereta ini.
65
11 дек. jawabannya diberikan oleh ShitalShah pada 11 Desember. 2016-12-11 05:05 '16 pada 5:05 pagi 2016-12-11 05:05

Apakah ini membantu menjawab pertanyaan Anda?

Saya tidak pernah menggunakan reinterpret_cast , dan saya bertanya-tanya apakah itu berfungsi jika dibutuhkan, tidak berbau desain yang buruk. Dalam basis kode saya bekerja pada dynamic_cast . Perbedaannya dengan static_cast adalah dynamic_cast melakukan pemeriksaan runtime, yang mungkin (lebih aman) atau mungkin tidak (lebih banyak overhead) seperti yang Anda inginkan (lihat msdn ).

12
01 дек. jawabannya diberikan andreas buykx 01 desember . 2008-12-01 23:20 '08 pada 11:20 2008-12-01 23:20

Selain sisa jawaban, masih ada contoh yang tidak jelas di mana static_cast tidak cukup, sehingga diperlukan reinterpret_cast . Misalkan ada fungsi yang dalam parameter output mengembalikan pointer ke objek dari kelas yang berbeda (yang tidak memiliki kelas basis umum). Contoh nyata dari fungsi tersebut adalah CoCreateInstance() (lihat Parameter Terakhir, yang sebenarnya void** ). Misalkan Anda meminta kelas objek tertentu dari fungsi ini, jadi Anda tahu sebelumnya jenis pointer (yang sering Anda lakukan untuk objek COM). Dalam hal ini, Anda tidak dapat memaksakan sebuah pointer pada pointer untuk void** menggunakan static_cast : Anda perlu reinterpret_cast<void**>(> .

Dalam kode:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), //static_cast<void**>( would give a compile error reinterpret_cast<void**>( ); 

Namun, static_cast berfungsi untuk pointer sederhana (bukan pointer ke pointer), sehingga kode di atas dapat ditulis u>reinterpret_cast (dengan harga variabel tambahan) sebagai berikut:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; void* tmp = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),  ); pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp); 
12
31 мая '15 в 17:16 2015-05-31 17:16 jawabannya diberikan oleh Serge Rogatch pada 31 Mei '15 pada 17:16 2015-05-31 17:16

Sementara jawaban lain menggambarkan dengan baik semua perbedaan antara kasta C ++, saya ingin menambahkan catatan singkat mengapa Anda tidak harus menggunakan pemeran gaya-C (Type) var dan Type(var) .

Untuk pemula C ++, gaya-C terlihat seperti operasi superset pada gips C ++ (static_cast <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> ()), dan seseorang mungkin lebih suka mereka daripada C ++. Bahkan, gaya C adalah superset dan lebih pendek untuk ditulis.

Masalah utama membawa gaya C adalah bahwa mereka menyembunyikan maksud sebenarnya dari pengembang selama pembuatan. Gaya C-style dapat melakukan hampir semua jenis casting dari sampah yang biasanya aman yang dilakukan oleh static_cast <> () dan dynamic_cast <> () ke peran yang berpotensi berbahaya, seperti const_cast <> (), di mana pengubah const dapat dihi>

Berikut ini contohnya.

 int a=rand(); // Random number. int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation. int* pa2=static_cast<int*>(a); // Compiler error. int* pa3=dynamic_cast<int*>(a); // Compiler error. int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo. *pa4=5; // Program crashes. 

Alasan utama mengapa C ++ ditambahkan ke bahasa adalah untuk memungkinkan pengembang untuk menjelaskan maksudnya - mengapa ia akan melakukannya. Menggunakan gips C-style yang hebat dalam C ++, Anda membuat kode Anda lebih mudah dibaca dan lebih rentan terhadap kesalahan, terutama untuk pengembang lain yang belum membuat kode Anda. Oleh karena itu, untuk membuat kode Anda lebih mudah dibaca dan eksplisit, Anda harus selalu lebih suka C ++ daripada casting atas gaya C-style.

Berikut adalah kutipan singkat dari Bjarne Stroustrup (penulis C ++) dari buku C ++ Bahasa pemrograman edisi ke 4 - hal. 302.

Pemain C-style ini jauh lebih berbahaya daripada operator transformasi bernama, karena menulis ke program yang kompleks lebih rumit, dan jenis konversi yang dimaksudkan untuk programmer tidak eksplisit.

6
22 авг. Jawabannya diberikan oleh Timmy_A 22 Agustus. 2018-08-22 14:18 '18 pada 14:18 2018-08-22 14:18

Untuk memahami, mari lihat cuplikan kode di bawah ini:

 struct Foo{}; struct Bar{}; int main(int argc, char** argv) { Foo* f = new Foo; Bar* b1 = f; // (1) Bar* b2 = static_cast<Bar*>(f); // (2) Bar* b3 = dynamic_cast<Bar*>(f); // (3) Bar* b4 = reinterpret_cast<Bar*>(f); // (4) Bar* b5 = const_cast<Bar*>(f); // (5) return 0; } 

Hanya baris (4) yang dikompilasi tanpa kesalahan. Hanya reinterpret_cast yang dapat digunakan untuk mengonversi pointer ke objek menjadi pointer ke jenis objek apa pun yang tidak terkait.

Yang berikut harus diperhatikan: dynamic_cast tidak akan bekerja pada saat runtime, namun pada kebanyakan kompiler tidak akan dikompilasi juga, karena struktur dari pointer yang dikonversi tidak memiliki fungsi virtual, yaitu, dynamic_cast hanya akan bekerja dengan pointer kelas polymorphic.,

Kapan menggunakan C ++ cast :

  • Gunakan static_cast sebagai setara dengan konversi tipe C yang mengubah nilai, atau ketika kita perlu secara eksplisit mengkonversi pointer dari kelas ke kelasnya.
  • Gunakan const_cast untuk menghapus kualifikasi const.
  • Gunakan reinterpret_cast untuk konversi tipe pointer yang tidak aman ke integer dan dari tipe pointer lain dan sebaliknya. Gunakan ini hanya jika kita tahu apa yang kita lakukan dan kita memahami masalah nama samaran.
0
21 дек. Jawabannya diberikan oleh Pankaj Kumar Thapa 21 Des. 2018-12-21 05:53 '18 pada 5:53 2018-12-21 05:53

Pertanyaan lain tentang label , atau Ajukan Pertanyaan