Apa penggunaan yang tepat dari:
static_cast
dynamic_cast
const_cast
reinterpret_cast
(jenis)nilai
jenis(nilai)
Bagaimana seseorang memutuskan untuk menggunakan di mana kasus-kasus tertentu?
static_cast
adalah pemain pertama yang anda harus mencoba untuk menggunakan. Melakukan hal-hal seperti konversi implisit antara jenis (seperti int
untuk mengambang
, atau pointer ke void*
), dan itu juga dapat menghubungi eksplisit fungsi konversi (atau implisit yang). Dalam banyak kasus, secara eksplisit menyatakan static_cast
isn't perlu, tapi itu's penting untuk dicatat bahwa T(sesuatu)
sintaks yang sama dengan (T)sesuatu
dan harus dihindari (lebih pada nanti). T(sesuatu, something_else)
lebih aman, namun, dan dijamin untuk memanggil konstruktor.
static_cast
juga dapat dilemparkan melalui warisan hierarki. Hal ini perlu ketika casting ke atas (ke arah kelas dasar), tapi ketika casting bawah ini dapat digunakan selama itu doesn't cast melalui virtual
warisan. Ia tidak melakukan pemeriksaan, namun, dan itu adalah tidak terdefinisi perilaku static_cast
turun hirarki untuk jenis yang isn't benar-benar jenis objek.
const_cast
dapat digunakan untuk menghilangkan atau menambahkan const
untuk variabel; tidak ada yang lain C++ cor mampu menghapus itu (bahkan tidak reinterpret_cast
). Hal ini penting untuk dicatat bahwa memodifikasi sebelumnya const
nilai hanya terdefinisi jika variabel asli adalah const
; jika anda menggunakannya untuk mengambil const
dari sebuah referensi untuk sesuatu yang bukan't dinyatakan dengan const
, itu lebih aman. Hal ini dapat berguna ketika overloading fungsi anggota berdasarkan const
, misalnya. Hal ini juga dapat digunakan untuk menambahkan const
untuk sebuah objek, seperti untuk memanggil fungsi anggota overload.
const_cast
juga bekerja sama pada volatile
, meskipun yang's kurang umum.
dynamic_cast
khusus digunakan untuk penanganan polimorfisme. Anda dapat melemparkan pointer atau referensi untuk setiap polymorphic untuk kelas lain jenis (polymorphic memiliki setidaknya satu fungsi virtual, dinyatakan atau diwariskan). Anda dapat menggunakannya untuk lebih dari sekedar casting ke bawah – anda dapat melemparkan ke samping atau bahkan sampai jaringan lain. The dynamic_cast
akan mencari objek yang diinginkan dan mengembalikannya jika mungkin. Jika hal ini dapat't, maka akan kembali nullptr
dalam kasus pointer, atau melempar std::bad_cast
dalam kasus referensi.
dynamic_cast
memiliki beberapa keterbatasan, meskipun. Itu doesn't bekerja jika ada beberapa objek dari jenis yang sama dalam warisan hierarki (yang disebut 'ditakuti diamond') dan anda tidak't menggunakan virtual
warisan. Hal ini juga hanya dapat pergi melalui semua warisan itu akan selalu gagal untuk melakukan perjalanan melalui dilindungi
atau pribadi
warisan. Hal ini jarang menjadi masalah, namun, seperti bentuk-bentuk warisan yang langka.
reinterpret_cast
adalah yang paling berbahaya cor, dan harus digunakan sangat hemat. Ternyata salah satu jenis langsung ke yang lain — seperti casting nilai dari satu pointer ke yang lain, atau menyimpan sebuah penunjuk pada sebuah int
, atau segala macam hal-hal buruk lainnya. Sebagian besar, satu-satunya jaminan yang anda dapatkan dengan reinterpret_cast
adalah bahwa biasanya jika anda melemparkan hasilnya kembali ke tipe yang asli, anda akan mendapatkan nilai yang sama persis (tapi tidak jika jenis menengah lebih kecil dari jenis asli). Ada jumlah konversi yang reinterpret_cast
tidak, terlalu. It's digunakan terutama untuk sangat aneh konversi dan sedikit manipulasi, seperti mengubah data mentah sungai menjadi data yang sebenarnya, atau menyimpan data dalam bit rendah dari sebuah penunjuk ke blok data.
Cast gaya C dan fungsi-gaya cor adalah cetakan yang menggunakan (jenis)objek
atau jenis(objek)
, masing-masing, dan secara fungsional setara. Mereka didefinisikan sebagai yang pertama dari berikut ini yang berhasil:
const_cast
static_cast
(meskipun mengabaikan pembatasan akses)static_cast
(lihat di atas), kemudian const_cast
reinterpret_cast
reinterpret_cast
, kemudian const_cast
Oleh karena itu dapat digunakan sebagai pengganti untuk melemparkan dalam beberapa kasus, tetapi bisa sangat berbahaya karena kemampuan untuk berpindah ke reinterpret_cast
, dan yang terakhir harus diutamakan ketika eksplisit casting diperlukan, kecuali anda yakin static_cast
akan berhasil atau reinterpret_cast
akan gagal. Bahkan kemudian, pertimbangkan lagi, lebih banyak pilihan eksplisit.
C-gaya gips juga mengabaikan akses kontrol saat melakukan static_cast
, yang berarti bahwa mereka memiliki kemampuan untuk melakukan operasi yang tidak ada pemain lain yang bisa. Ini adalah sebagian besar kludge, meskipun, dan dalam pikiran saya adalah hanya alasan lain untuk menghindari C-gaya gips.
Gunakan dynamic_cast
untuk mengubah pointer/referensi dalam warisan hirarki.
Gunakan static_cast
biasa untuk jenis konversi.
Gunakan reinterpret_cast
untuk tingkat rendah menafsirkan dari pola-pola bit. Gunakan dengan sangat hati-hati.
Gunakan const_cast
untuk casting const/volatile
. Menghindari hal ini, kecuali jika anda terjebak menggunakan const-benar API.
(Banyak teoretis dan konseptual penjelasan yang telah diberikan di atas)
Berikut ini adalah beberapa contoh-contoh praktis ketika saya digunakan static_cast, dynamic_cast, const_cast, reinterpret_cast.
(Juga menunjukkan 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 e.g.
// 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/* if( ... )*/{
// ...
}
}
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*>(&val), 2);
}
Mungkin akan membantu jika anda tahu sedikit dari internal...
static_cast
static_cast
bagi mereka.A
ke B
, static_cast
panggilan B
's konstruktor lewat A
sebagai param. Atau, A
bisa memiliki konversi operator (yaitu A::operator B()
). Jika B
doesn't memiliki konstruktor, atau A
doesn't memiliki konversi operator, maka anda mendapatkan compile time error. A*
ke B *
selalu berhasil jika A dan B adalah warisan hirarki (atau void) jika anda mendapatkan kesalahan kompilasi.A&
ke B &
.dynamic_cast
(Dasar*)
untuk (Berasal*)
mungkin gagal jika pointer tidak benar-benar berasal dari jenis.A*
ke B*
, jika pemain tidak valid maka dynamic_cast akan kembali nullptr.A&
ke B &
jika pemain tidak valid maka dynamic_cast akan membuang bad_cast terkecuali.const_cast
set<T>
yang hanya mengembalikan unsur-unsurnya sebagai const untuk memastikan anda don't mengubah kunci. Namun jika niat anda adalah untuk memodifikasi objek's non-anggota kunci maka harus ok. Anda dapat menggunakan const_cast untuk menghapus constness.T& SomeClass::foo()
serta const T& SomeClass::foo() const
. Untuk menghindari duplikasi kode, anda dapat menerapkan const_cast untuk mengembalikan nilai dari satu fungsi dari yang lain.reinterpret_cast
Tidak ini menjawab pertanyaan anda?
Aku belum pernah digunakan reinterpret_cast
, dan bertanya-tanya apakah berjalan ke hal yang perlu isn't bau dari desain yang buruk. Dalam kode tempat saya bekerja pada dynamic_cast
lebih banyak digunakan. Perbedaan dengan static_cast
itu dynamic_cast
tidak runtime memeriksa yang mungkin (lebih aman) atau tidak (lebih overhead) menjadi apa yang anda inginkan (lihat baca).
Selain jawaban yang lain sejauh ini, di sini adalah unobvious contoh di mana static_cast
tidak cukup sehingga reinterpret_cast
yang dibutuhkan. Misalkan terdapat sebuah fungsi yang di output parameter mengembalikan pointer ke objek dari kelas yang berbeda (yang tidak berbagi dasar umum kelas). Contoh nyata dari fungsi tersebut adalah CoCreateInstance()
(lihat parameter terakhir, yang sebenarnya adalah batal**
). Misalkan anda meminta kelas tertentu dari objek dari fungsi ini, sehingga anda mengetahui terlebih dahulu jenis pointer (yang sering anda lakukan untuk objek COM). Dalam hal ini anda tidak dapat melemparkan pointer ke pointer anda ke void**
dengan static_cast
: anda perlu reinterpret_cast<void**>(&yourPointer)
.
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**>(&pNetFwPolicy2) would give a compile error
reinterpret_cast<void**>(&pNetFwPolicy2) );
Namun, static_cast
bekerja untuk sederhana pointer (bukan pointer ke pointer), sehingga kode di atas dapat ditulis ulang untuk menghindari reinterpret_cast
(dengan harga tambahan variabel) dengan cara 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),
&tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);
Sementara jawaban yang lain baik dijelaskan semua perbedaan antara C++ gips, saya ingin menambahkan catatan singkat mengapa anda tidak harus menggunakan C-gaya gips (Jenis) var
dan Jenis(var)
.
Untuk C++ pemula C-gaya gips terlihat seperti sedang superset operasi lebih dari C++ gips (static_cast<>(), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) dan seseorang bisa lebih memilih mereka atas C++ gips. Pada kenyataannya cast gaya C adalah superset dan lebih pendek untuk menulis.
Masalah utama dari C-gaya gips adalah bahwa mereka bersembunyi pengembang maksud sebenarnya dari para pemain. C-gaya gips dapat melakukan hampir semua jenis pengecoran dari biasanya aman gips dilakukan oleh static_cast<>() dan dynamic_cast<>() berpotensi berbahaya gips seperti const_cast<>(), di mana const pengubah dapat dihapus sehingga const variabel yang dapat dimodifikasi dan reinterpret_cast<>() yang bahkan dapat menafsirkan nilai-nilai integer pointer.
Berikut ini adalah contoh.
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++ gips yang ditambahkan ke dalam bahasa adalah untuk memungkinkan pengembang untuk memperjelas niatnya - mengapa ia akan melakukan itu cast. Dengan menggunakan C-gaya gips yang sah dalam C++ anda membuat kode anda lebih mudah dibaca dan lebih rawan kesalahan terutama bagi pengembang lain yang tidak't membuat kode anda. Jadi untuk membuat kode anda lebih mudah dibaca dan eksplisit anda harus selalu memilih C++ gips di atas C-gaya gips.
Berikut adalah kutipan singkat dari Bjarne Stroustrup's (penulis C++) buku Bahasa Pemrograman C++ edisi 4 - halaman 302.
Ini cast gaya C ini jauh lebih berbahaya daripada yang bernama konversi operator karena notasi ini lebih sulit untuk spot dalam sebuah program besar dan jenis konversi yang dimaksudkan oleh si programmer tidak eksplisit.
Untuk memahami, let's mempertimbangkan berikut cuplikan kode:
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 garis (4) menyusun tanpa kesalahan. Hanya reinterpret_cast dapat digunakan untuk mengkonversi sebuah pointer ke objek untuk pointer ke suatu apapun terkait jenis objek.
Satu hal yang harus dicatat adalah: dynamic_cast akan gagal pada saat run-time, namun pada sebagian besar kompiler juga akan gagal untuk mengkompilasi karena tidak ada fungsi virtual dalam struct pointer yang dicor, arti dynamic_cast akan bekerja dengan hanya polimorfik kelas pointer.
Ketika menggunakan C++ cor: