Saya pernah mendengar bahwa static_cast
fungsi tersebut lebih disukai daripada C-style atau casting fungsi-gaya sederhana. Apakah ini benar? Mengapa?
Saya pernah mendengar bahwa static_cast
fungsi tersebut lebih disukai daripada C-style atau casting fungsi-gaya sederhana. Apakah ini benar? Mengapa?
Jawaban:
Alasan utama adalah bahwa C gips klasik tidak membuat perbedaan antara apa yang kita sebut static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
, dan dynamic_cast<>()
. Keempat hal ini sangat berbeda.
A static_cast<>()
biasanya aman. Ada konversi yang valid dalam bahasa, atau konstruktor yang sesuai yang memungkinkan. Satu-satunya waktu itu agak berisiko adalah ketika Anda melemparkan ke kelas yang diwariskan; Anda harus memastikan bahwa objek tersebut sebenarnya adalah keturunan yang Anda klaim itu, dengan cara eksternal ke bahasa (seperti bendera di objek). A dynamic_cast<>()
aman selama hasilnya dicentang (pointer) atau pengecualian yang mungkin diperhitungkan (referensi).
A reinterpret_cast<>()
(atau a const_cast<>()
) di sisi lain selalu berbahaya. Anda memberi tahu kompiler: "percayalah padaku: Saya tahu ini tidak terlihat seperti foo
(sepertinya tidak bisa diubah), tetapi".
Masalah pertama adalah bahwa hampir tidak mungkin untuk mengetahui mana yang akan terjadi dalam pemeran gaya-C tanpa melihat potongan kode yang besar dan membubarkan dan mengetahui semua aturan.
Mari kita asumsikan ini:
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Sekarang, keduanya dikompilasi dengan cara yang sama:
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
Namun, mari kita lihat kode yang hampir identik ini:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
Seperti yang Anda lihat, tidak ada cara mudah untuk membedakan antara dua situasi tanpa mengetahui banyak tentang semua kelas yang terlibat.
Masalah kedua adalah bahwa gips C-style terlalu sulit untuk ditemukan. Dalam ekspresi yang kompleks, sangat sulit untuk melihat para pemeran gaya-C. Hampir tidak mungkin untuk menulis alat otomatis yang perlu menemukan gips gaya-C (misalnya alat pencarian) tanpa front-end kompiler C ++ yang penuh. Di sisi lain, mudah untuk mencari "static_cast <" atau "reinterpret_cast <".
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
Itu berarti bahwa, tidak hanya para pemain gaya-C yang lebih berbahaya, tetapi jauh lebih sulit untuk menemukan mereka semua untuk memastikan bahwa mereka benar.
static_cast
untuk menurunkan hierarki warisan, melainkan dynamic_cast
. Itu akan mengembalikan pointer nol atau pointer yang valid.
static_cast
dalam situasi itu. dynamic_cast
mungkin lebih aman, tetapi itu tidak selalu merupakan pilihan terbaik. Kadang-kadang Anda tahu bahwa pointer menunjuk ke subtipe yang diberikan, dengan cara buram ke kompiler, dan a static_cast
lebih cepat. Dalam setidaknya beberapa lingkungan, dynamic_cast
memerlukan dukungan kompiler opsional dan biaya runtime (mengaktifkan RTTI), dan Anda mungkin tidak ingin mengaktifkannya hanya untuk beberapa pemeriksaan yang dapat Anda lakukan sendiri. RTTI C ++ hanyalah satu kemungkinan solusi untuk masalah ini.
static_cast
. C ekivalen reinterpret_cast
adalah *(destination_type *)&
, yaitu mengambil alamat objek, casting alamat itu ke pointer ke tipe yang berbeda, dan kemudian dereferencing. Kecuali dalam kasus tipe karakter atau tipe struct tertentu yang C mendefinisikan perilaku konstruk ini, umumnya menghasilkan perilaku yang tidak terdefinisi dalam C.
int
(dan int
sendiri), mengapa menggunakan static_cast<int>
vs (int)
sebagai satu-satunya manfaat tampaknya dengan variabel kelas dan pointer. Minta agar Anda menjelaskan hal ini.
int
dynamic_cast
tidak berlaku, tetapi semua alasan lainnya berlaku. Sebagai contoh: katakanlah v
parameter fungsi dinyatakan sebagai float
, maka (int)v
adalah static_cast<int>(v)
. Tetapi jika Anda mengubah parameter untuk float*
, (int)v
diam-diam menjadi reinterpret_cast<int>(v)
sementara static_cast<int>(v)
adalah ilegal dan benar tertangkap oleh compiler.
Satu tip pragmatis: Anda dapat dengan mudah mencari kata kunci static_cast dalam kode sumber Anda jika Anda berencana untuk merapikan proyek.
int
parameter tunggal .
Singkatnya :
static_cast<>()
memberi Anda kemampuan memeriksa waktu kompilasi, pemeran C-Style tidak.static_cast<>()
dapat terlihat dengan mudah di mana saja di dalam kode sumber C ++; sebaliknya, pemeran C_Style lebih sulit dikenali.- Niat disampaikan jauh lebih baik menggunakan gips C ++.
Penjelasan Lebih Lanjut :
Para pemain statis melakukan konversi antara tipe yang kompatibel . Ini mirip dengan para pemeran C-style, tetapi lebih membatasi. Sebagai contoh, pemeran gaya-C akan memungkinkan pointer integer untuk menunjuk ke char.
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
Karena ini menghasilkan pointer 4-byte yang menunjuk ke 1 byte dari memori yang dialokasikan, menulis ke pointer ini akan menyebabkan kesalahan run-time atau akan menimpa beberapa memori yang berdekatan.
*p = 5; // run-time error: stack corruption
Berbeda dengan cast gaya-C, cast statis akan memungkinkan compiler untuk memeriksa apakah tipe data pointer dan pointee kompatibel, yang memungkinkan programmer untuk menangkap tugas pointer yang salah ini selama kompilasi.
int *q = static_cast<int*>(&c); // compile-time error
Baca lebih lanjut tentang:
Apa perbedaan antara static_cast <> dan style casting C
dan
pemain reguler vs static_cast vs dynamic_cast
static_cast<>()
itu lebih mudah dibaca. Maksudku, kadang - kadang , tetapi sebagian besar waktu - terutama pada tipe integer dasar - itu hanya verbose yang mengerikan dan tidak perlu. Sebagai contoh: Ini adalah fungsi yang menukar byte kata 32-bit. Akan hampir mustahil untuk membaca menggunakan static_cast<uint##>()
gips, tetapi cukup mudah dimengerti menggunakan (uint##)
gips. Gambar kode: imgur.com/NoHbGve
always
. (Tapi sebagian besar kali ya) Ada kasus di mana para pemeran gaya c jauh lebih mudah dibaca. Itulah salah satu alasan casting gaya c masih hidup dan menendang c ++ imho. :) Ngomong-ngomong itu contoh yang sangat bagus
(uint32_t)(uint8_t)
) untuk mencapai itu selain byte terendah diatur ulang. Untuk itu ada bitwise dan ( 0xFF &
). Penggunaan gips mengaburkan niat.
Pertanyaannya lebih besar dari hanya menggunakan wither static_cast atau casting gaya C karena ada hal-hal berbeda yang terjadi ketika menggunakan cast gaya C. Operator casting C ++ dimaksudkan untuk membuat operasi ini lebih eksplisit.
Pada permukaan static_cast dan gips gaya C muncul untuk hal yang sama, misalnya ketika casting satu nilai ke yang lain:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
Keduanya memberikan nilai integer menjadi ganda. Namun ketika bekerja dengan pointer hal menjadi lebih rumit. beberapa contoh:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
Dalam contoh ini (1) mungkin OK karena objek yang ditunjukkan oleh A benar-benar sebuah instance dari B. Tetapi bagaimana jika Anda tidak tahu pada titik itu dalam kode apa yang sebenarnya ditunjukkan oleh sebuah? (2) mungkin sangat legal (Anda hanya ingin melihat satu byte dari integer), tetapi bisa juga merupakan kesalahan dalam hal mana kesalahan akan lebih baik, seperti (3). Operator casting C ++ dimaksudkan untuk mengekspos masalah ini dalam kode dengan memberikan kesalahan waktu kompilasi atau run-time jika memungkinkan.
Jadi, untuk "value casting" yang ketat, Anda dapat menggunakan static_cast. Jika Anda ingin menjalankan pointer waktu polimorfik menggunakan dynamic_cast. Jika Anda benar-benar ingin melupakan jenis, Anda dapat menggunakan reintrepret_cast. Dan untuk hanya membuang const ke luar jendela ada const_cast.
Mereka hanya membuat kode lebih eksplisit sehingga Anda tahu apa yang Anda lakukan.
static_cast
berarti Anda tidak dapat secara tidak sengaja const_cast
atau reinterpret_cast
, yang merupakan hal yang baik.
Lihat Pengantar C ++ yang Efektif
Ini tentang berapa banyak jenis keamanan yang ingin Anda terapkan.
Ketika Anda menulis (bar) foo
(yang setara dengan reinterpret_cast<bar> foo
jika Anda belum menyediakan operator konversi tipe) Anda memberi tahu kompiler untuk mengabaikan keamanan jenis, dan lakukan apa yang diperintahkan.
Ketika Anda menulis, static_cast<bar> foo
Anda meminta kompiler untuk setidaknya memeriksa bahwa konversi tipe masuk akal dan, untuk tipe integral, untuk memasukkan beberapa kode konversi.
EDIT 2014-02-26
Saya menulis jawaban ini lebih dari 5 tahun yang lalu, dan saya salah. (Lihat komentar.) Tapi itu masih mengalami peningkatan!
static_cast<bar>(foo)
dengan kurung. Sama untuk reinterpret_cast<bar>(foo)
.
C style cast mudah dilewatkan dalam satu blok kode. Gips gaya C ++ bukan hanya praktik yang lebih baik; mereka menawarkan tingkat fleksibilitas yang jauh lebih besar.
reinterpret_cast memungkinkan konversi tipe integral ke penunjuk, namun dapat menjadi tidak aman jika disalahgunakan.
static_cast menawarkan konversi yang baik untuk tipe numerik misalnya dari mulai enum ke int atau ints hingga float atau tipe data apa pun yang Anda yakini. Itu tidak melakukan pemeriksaan run time.
dynamic_cast di sisi lain akan melakukan pemeriksaan ini menandai penandaan atau konversi yang ambigu. Ini hanya bekerja pada petunjuk dan referensi dan menimbulkan overhead.
Ada beberapa yang lain tetapi ini adalah yang utama yang akan Anda temui.
static_cast, selain memanipulasi pointer ke kelas, juga dapat digunakan untuk melakukan konversi yang didefinisikan secara eksplisit di kelas, serta untuk melakukan konversi standar antara tipe dasar:
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast<int>(d)
, padahal (int)d
jauh lebih singkat dan mudah dibaca? (Maksud saya dalam kasus tipe dasar, bukan pointer objek.)
(int)d
ketika int{d}
jauh lebih mudah dibaca? Konstruktor, atau fungsi-seperti jika Anda miliki ()
, sintaksis hampir tidak begitu cepat untuk beralih ke labirin tanda kurung mimpi buruk dalam ekspresi kompleks. Dalam hal ini, itu int i{d}
bukan int i = (int)d
. IMO yang jauh lebih baik. Yang mengatakan, ketika saya hanya perlu sementara dalam ekspresi, saya menggunakan static_cast
dan tidak pernah menggunakan gips konstruktor, saya tidak berpikir. Saya hanya menggunakan (C)casts
ketika buru-buru menulis debug cout
...