Static_cast, dynamic_cast, const_cast və reinterpret_cast nə vaxt istifadə edilməlidir?

Düzgün istifadə nədir:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C-stil (type)value
  • type(value) tərzi döküm

Hansı hallarda istifadə edəcəyinizə necə qərar verirsiniz?

2153
01 дек. e.James tərəfindən təyin 01 Dekabr. 2008-12-01 23:11 '08 at 11:11 pm 2008-12-01 23:11
@ 8 cavab

static_cast istifadə etməyiniz lazım olan ilk static_cast . Bu, növlər arasında gizli dönüşümlər (məsələn, int üçün float və ya bir işaretçi void* ) kimi şeylər edir və həmçinin açıq dönüşüm funksiyalarını (və ya örtülü olanları) çağırır. Bir çox hallarda, static_cast açıq bir şəkildə ifadə edilmir, lakin qeyd etmək lazımdır ki, sözdizimi T(something) bərabərdir və bundan qaçınmaq lazımdır (bundan sonra daha çox). A T(something, something_else) təhlükəsiz və buna baxmayaraq, konstruktor çağırmaq üçün zəmanətdir.

static_cast də miras hiyerarşiləri vasitəsilə həyata keçirilə bilər. Bu, (aşağı sinifə doğru) atmaqda lazım deyil, ancaq aşağı düşərkən virtual mirasa devralıncaya qədər istifadə edilə bilər. Lakin, doğrulama aparılmır və hiyerarşiyi aşağıda göstərmək üçün static_cast ilə müəyyənləşdirilməyən davranış həqiqətən bir obyekt növü olmayan bir növüdür.


const_cast bir dəyişənə const çıxarmaq və ya əlavə etmək üçün istifadə edilə bilər; heç bir digər C ++ üsulu onu aradan qaldıra bilmir (hətta reinterpret_cast ). Qeyd edək ki, const əvvəlki dəyərindəki dəyişiklik yalnız əvvəlcədən dəyişən const olduqda müəyyən edilmir; const istifadə edərək elan edilməmiş bir şeyə bir const bağlantısını aradan qaldırmaq üçün istifadə edirsinizsə, bu təhlükəsizdir. Bu, məsələn, const əsasında üzv funksiyalarının yüklənməsində faydalı ola bilər. Bu, həmçinin, bir obyektin üst- const çağırmaq üçün bir obyektə const əlavə etmək üçün də istifadə edilə bilər.

const_cast ayrıca, bu daha az yaygın olmasına baxmayaraq, volatile olaraq işləyir.


dynamic_cast demək olar ki, yalnız polimorfizmi emal üçün istifadə olunur. Hər hansı digər tipdə hər hansı bir polimorfik tipə bir pointer və ya bir keçid yerləşdirə bilərsiniz (bir polimorfik növü elan edilmiş və ya miras alınmış ən azı bir virtual funksiyası var). Yalnız onu atmadan daha çox istifadə edə bilərsiniz - onu yanlara və ya başqa bir zəncirə atmaq olar. dynamic_cast istənilən obyekti dynamic_cast və mümkünsə, onu qaytarın. Əgər mümkün deyilsə, bir göstərici vəziyyətində nullptr qaytarılacaq və ya bir std::bad_cast .

dynamic_cast bəzi məhdudiyyətlər var. Miras hiyerarşisində (eyni zamanda "qorxunc almaz") eyni tipli bir neçə obyekt varsa, işləmir və virtual mirasdan istifadə etməyin. O, həmçinin yalnız ictimai miras vasitəsilə keçə bilər - həmişə miras yolu ilə protected və ya private daşıyacaqdır. Bu nadir hallarda problemdir, çünki mirasın bu cür formaları nadirdir.


reinterpret_cast ən təhlükəli atışdır və çox az istifadə edilməlidir. Bir növü birbaşa digərinə çevrilir - məsələn, bir göstəricidən digərinə dəyər verərək və ya göstəricini int ya da hər cür digər xoşagəlməz şeylərə qənaət etməklə. Əsasən, reinterpret_cast ilə əldə etdiyiniz yeganə zəmanət, nəticəni orijinal növə qaytarırsan, eyni dəyəri əldə edəcəksiniz (lakin ara növü orijinal növündən kiçik olsa). reinterpret_cast çıxış edə bilməyən bir sıra dəyişikliklər var. Əsasən xüsusilə qəribə dəyişikliklər və bits ilə manipulyasiyalar üçün, məsələn, xammal məlumat axını faktiki məlumatlara çevirmək və ya göstərilən göstəricinin aşağı hissələrində məlumatların saxlanması kimi istifadə edilmişdir.


<Style >> stil siyahısı sırasıyla bir cast (type)object və ya type(object) . C-stil siyahısı aşağıda göstərilənlərdən biri kimi müəyyən edilir:

  • const_cast
  • static_cast (giriş məhdudiyyətlərinə baxmayaraq)
  • static_cast (yuxarıda bax), sonra const_cast
  • reinterpret_cast
  • reinterpret_cast , sonra const_cast

Bəzi hallarda bu digər hayaletlərin əvəzi kimi istifadə oluna bilər, ancaq, static_cast müvəffəqiyyətli olacağına və ya reinterpret_cast ilə sona çatacağına əmin olmadıqda, açıq bir döküm tələb olunduğunda, reinterpret_cast a daxil olma qabiliyyətinə görə son dərəcə təhlükəli ola bilər. səhvən. Hətta daha uzun, daha açıq bir variant düşünün.

C-stil static_cast , static_cast yerinə yetirərkən çıxış nəzarətini static_cast , yəni başqa bir static_cast çıxış edə bilməyəcəyi bir əməliyyatı yerinə yetirmək qabiliyyətinə malikdir. Bu əsasən çınqıl və mənim fikrimcə, bu, C stilinin çəkilməməsi üçün başqa bir səbəbdir.

2286
01 дек. cavab coppro 01 dek verilir . 2008-12-01 23:26 '08 at 11:26 pm 2008-12-01 23:26

Göstərici / keçid devralma hiyerarşiyəsinə çevirmək üçün dynamic_cast istifadə edin.

Normal növ dönüşümlər üçün static_cast istifadə edin.

border=0

Bit nişanlarının aşağı səviyyədə yenidən reinterpret_cast üçün reinterpret_cast istifadə edin. Həddindən artıq ehtiyatla istifadə edin.

const_cast istifadə edin const/volatile . Yanlış bir API istifadə etmədiyiniz təqdirdə onu çəkinin.

298
01 дек. Fred Larsonun verdiyi cavabı 01 Dekabr. 2008-12-01 23:22 '08 at 11:22 2008-12-01 23:22

(Bir çox nəzəri və konseptual şərhlər yuxarıda verilmişdir)

Static_cast , dynamic_cast , const_cast , reinterpret_cast istifadə etdikdə aşağıdakı praktiki nümunələrdən bəziləri.

(Həmçinin bu izahı anlamaq üçün buna aiddir: 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 янв. Cavab Sumit Arora Jan 21 tərəfindən verilir 2014-01-21 07:53 '14 da 7:53 2014-01-21 07:53

Bir az daxili bildiyinizdə kömək edə bilər ...

static_cast

  • C ++ kompilyatoru float kimi miqyaslama növlərini int üçün necə əvvəldən bilir. static_cast üçün static_cast istifadə edin.
  • Kompilyatorun A dan B ə çevrilməsini xahiş etdikdə, static_cast konstruktor B çağırır B parametr kimi A keçir. Alternativ olaraq, A transform operatoru ola bilər (yəni A::operator B() ). B belə bir konstruktor yoxsa ya da transformasiyalı operatora sahib deyilsə, kompilyasiya zamanı səhvini alacaqsınız.
  • A və B-nin devralma (və ya boşluq) hiyerarşisi olduqda A* -dan B* A* -ə çevrilməsi B* zaman uğurlu olur, əks halda kompilyasiya səhviniz olacaq.
  • Düzeltme : əsas göstərici törətdiyi göstəriciyə köçürsəniz, lakin faktiki obyekt həqiqətən törəmə bir növü olmasa, səhv ala bilməzsiniz. Siz pis bir pointer və çox güman ki, runtime bir segfault almaq. Eyni A> B> gedir.
  • Got : tirajdan Baza'ya və ya tam əksinə yeni bir kopiya yaradacaq! C # / Java'dan gələn insanlar üçün bu, böyük bir sürpriz ola bilər, çünki nəticə əsasən Derived-dən yaradılmış bir kəsilmiş obyektdir.

Dinamik

  • dynamic_cast bir dökümün etibarlı olub-olmadığını müəyyən etmək üçün runtime növü məlumatını istifadə edir. Məsələn, göstərici əslində törəmə bir növü olmadıqda (Base*) dən (Derived*) verə bilər.
  • Dinamik mətn static_cast ilə müqayisədə çox bahadır!
  • A* B'den B* , əgər döküm səhv olarsa, dinamik_azq nullptr qayıdır.
  • A> B> üçün, cast doğru deyilsə, dinamik_az bir bad_cast istisna atacaq.
  • Digər ghosts fərqli olaraq, bir runtime overhead var.

const_cast

  • Static_cast qeyri-sabit sabitləri edə bilər, fərqli bir yol izləyə bilməz. Const_cast hər iki istiqamətdə də işləyə bilər.
  • Bunun rahat olduğu bir nümunə bir konteyner vasitəsi ilə yinelemek, məsələn, onun əsasını dəyişdirməməyinizə əmin olmaq üçün yalnız elementləri döndərən set<T> . Ancaq niyyətiniz obyektin qeyri-əsas üzvlərini dəyişdirməkdirsə, hər şey yaxşı olmalıdır. Const_cast-dan istifadə etmək üçün konstseni ləğv edə bilərsiniz.
  • T foo() const T foo() tətbiq etmək istədiyiniz zaman başqa bir nümunədir. Kod çoğaltılmasını qarşısını almaq üçün, bir funksiyanın dəyərini digərindən qaytarmaq üçün const_cast istifadə edə bilərsiniz.

reinterpret_cast

  • Əsasən bu yaddaş yerində bu baytları götürmək və onu müəyyən bir obyekt kimi qəbul etmək deyir.
  • Məsələn, bitlərin bir üzən nöqtədə göründüyünü görmək üçün bir tamsayı ilə 4 bayta bir üzən nöqtə ilə 4 bayt yükləyə bilərsiniz.
  • Şübhəsiz ki, məlumatların növü uyğun deyilsə, bir segfault əldə edə bilərsiniz.
  • Bu qatar üçün heç bir zaman məsafəsi yoxdur.
65
11 дек. Cavab ShitalShah 11 Dekabr. 2016-12-11 05:05 '16 'da saat 5:05 ' də 2016-12-11 05:05

Bu sual sualınıza cavab vermirmi?

Mən heç vaxt reinterpret_cast istifadə etməmişdim və istərdim ki, işlə məşğul olsaydı, pis dizaynı qoxmur. Kod bazasında dynamic_cast üzərində işləyirəm. static_cast ile olan static_cast , dynamic_cast bir static_cast (daha güvenli) ya da olamayacağınız (daha fazla yerden ) istediğiniz ( msdn'e bakın ) bir çalışma süresi kontrolünü gerçekleştirmesidir .

12
01 дек. Cavab verilir andreas buykx 01 dek. 2008-12-01 23:20 '08 at 11:20 2008-12-01 23:20

static_cast qalan hissəsinə əlavə olaraq static_cast kifayət deyil, hələ də reinterpret_cast tələb olunur qeyri-aydın bir nümunə var. Çıxış parametresinde farklı sınıfların (ümumi temel sınıfı olmayan) nesnelere döndürdüğünü gösteren bir funksiya olduğunu varsayalım. Belə bir funksiyanın gerçək nümunəsi CoCreateInstance() (baxın ki, həqiqətən CoCreateInstance() olan son Parametrə baxın). Bu funksiyadan xüsusi bir obyekt sinfi tələb edirsiniz, buna görə də əvvəlcədən pointer tipini (tez-tez COM obyektləri üçün etdiyiniz) bilirsiniz. Bu halda, static_cast istifadə edərək, bir göstəriciyə bir göstərici tətbiq edə bilməzsiniz: reinterpret_cast<void**>(> .

Kodda:

 #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**>( ); 

Lakin, static_cast sadə göstəricilər üçün işləyir (göstəriciyə göstəricilər deyil), beləliklə, yuxarıdakı kod reinterpret_cast (əlavə dəyişən qiymətə) qarşısını almaq üçün yenidən yazıla bilər:

 #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 Cavab Serge Rogatch tərəfindən 31 May 'da 17:16' də verilir 2015-05-31 17:16

Digər cavablarda C ++ kələmləri arasındakı fərqlər yaxşı təsvir edilsə də, mən C-stili (Type) varType(var) istifadə etməməyiniz üçün qısa bir qeyd əlavə etmək istərdim.

C ++ başlanğıcı üçün C-style C ++-da (static_cast <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> ()) üstündə bir əməliyyat kimi görünür və kimsə C ++ üzərindən üstün ola bilər. Əslində, C-stili yazmaq üçün daha çox və daha qısadır.

C üslubunun gətirilməsinin əsas problemi yaradılması zamanı yaradıcı niyyətinin gizlənməsidir. C-stil üslubları const_cast <> () kimi potensial təhlükəli rollara static_cast <> () və dynamic_cast <> () tərəfindən normal təhlükəsiz zibildən çıxarmaq demək olar ki, bütün növləri həyata keçirə bilər; dəyişənlər dəyişə bilər və reinterpret_cast <> (), tam ədədi göstəricilərə hətta yenidən şərh edə bilər.

Bir nümunə.

 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. 

C ++ dilinin dilinə əlavə olunmasının əsas səbəbi, inkişaf etməkdə olan niyyətinin aydınlaşdırılmasına imkan vermək idi. C ++ -də böyük olan C-stil arxivlərini istifadə edərək kodunuzu daha az oxunaqlı və daha çox səhvlərə yönəldirsiniz, xüsusən kodu yaratmadığınız digər inkişafçılar üçün. Buna görə, kodunuzu daha oxunaqlı və aydın etmək üçün C-style üslubları üzərində hər zaman C ++-ə üstünlük verməlisiniz.

Burada 4-cü nəşrin C ++ Proqramlaşdırma dili olan Bjarne Stroustrup (C ++ yazıçısı) tərəfindən qısa bir qiymət verilir - s. 302.

Bu C-stil tökmə adını dəyişdirmə operatorlarından daha təhlükəlidir, çünki kompleks bir proqrama yazma daha mürəkkəbdir və proqramçı üçün nəzərdə tutulan dönüşüm növü aydın deyil.

6
22 авг. Cavab Timmy_A 22 aug tərəfindən verilir . 2018-08-22 14:18 '18 saat 02:18 'da 2018-08-22 14:18

Anlamaq üçün aşağıdakı kod parçasına baxaq:

 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; } 

Yalnız xətt (4) səhvsiz tərtib edilir. Yalnız reinterpret_cast bir göstərici obyektin hər hansı bir əlaqəsi olmayan obyektə bir göstəriciyə çevirmək üçün istifadə edilə bilər.

Aşağıda qeyd edilməlidir: dinamik_time iş zamanı işləməyəcək, ancaq bir çox kompilyatorda onu tərtib etməyəcəkdir, çünki işarəçi strukturu virtual funksiyaları olmayan, yəni dinamik mətn yalnız polimorfik sinif göstəriciləri ilə işləyəcəkdir.

C ++ oyununu istifadə edərkən :

  • Static_cast'i dəyərləri çevirən bir növ C dönüşümünün bərabərliyi kimi istifadə edin və ya göstəriciyi bir sinifdən üstün sinifə çevirməliyik.
  • Const seçicisini çıxarmaq üçün const_cast istifadə edin.
  • Təhlükəli pointer növü çevrilməsini integer və digər göstərici növlərindən və əksinə reinterpret_cast istifadə edin. Bunu yalnız nə etdiyimizi bildiyimiz halda istifadə edin və yalançıların problemlərini anlayırıq.
0
21 дек. Cavab Pankaj Kumar Thapa tərəfindən verilir 21 dekabr. 2018-12-21 05:53 '18 at 5:53 2018-12-21 05:53

yazıları ilə bağlı digər suallar: və ya sual verin