Kiedy należy stosować odlew statyczny, odlew dynamiczny,odlew const i reinterpret?

Jakie są właściwe zastosowania:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C-style cast (type)value
  • Obsada w stylu funkcyjnym type(value)

W Jaki Sposób można zdecydować, które z konkretnych przypadków użyć?

Author: user3728501, 2008-12-01

7 answers

static_cast to pierwsza Obsada, którą powinieneś spróbować użyć. Robi rzeczy takie jak niejawne konwersje między typami (takie jak int do float lub wskaźnik do void*), a także może wywoływać jawne funkcje konwersji (lub niejawne). W wielu przypadkach jawne podanie static_cast nie jest konieczne, ale ważne jest, aby pamiętać, że składnia T(something) jest równoważna (T)something i należy jej unikać (więcej na ten temat później). A T(something, something_else) jest jednak bezpieczna i gwarantowana, że zadzwoni do konstruktor.

static_cast może również rzucać poprzez hierarchie dziedziczenia. Nie jest to konieczne podczas rzucania w górę (w kierunku klasy bazowej), ale podczas rzucania w dół może być używane tak długo, jak nie rzuca przez dziedziczenie virtual. Nie sprawdza jednak i jest niezdefiniowanym zachowaniem static_cast w dół hierarchii do typu, który w rzeczywistości nie jest typem obiektu.


const_cast może być użyty do usunięcia lub dodania const do zmiennej; żaden inny C++ nie jest zdolne do jego usunięcia (nawet reinterpret_cast). Ważne jest, aby pamiętać, że modyfikowanie dawnej wartości const jest niezdefiniowane tylko wtedy, gdy oryginalna zmienna to const; jeśli użyjesz jej do usunięcia const Z odniesienia do czegoś, co nie zostało zadeklarowane przez const, jest to bezpieczne. Może to być przydatne np. podczas przeciążania funkcji składowych opartych na const. Może być również użyty do dodania const do obiektu, na przykład do wywołania funkcji member overload.

const_cast działa również podobnie na volatile, choć to mniej powszechne.


dynamic_cast jest prawie wyłącznie używany do obsługi polimorfizmu. Możesz rzucić wskaźnik lub odniesienie do dowolnego typu polimorficznego na dowolny inny typ klasy (Typ polimorficzny ma co najmniej jedną funkcję wirtualną, zadeklarowaną lub dziedziczoną). Możesz go używać nie tylko do rzucania w dół - możesz rzucać na boki lub nawet w górę innego łańcucha. dynamic_cast wyszukuje żądany obiekt i zwraca go, jeśli to możliwe. Jeśli nie może, powróci nullptr W w przypadku wskaźnika, lub rzut std::bad_cast w przypadku odniesienia.

dynamic_cast ma jednak pewne ograniczenia. To nie działa, jeśli w hierarchii dziedziczenia znajduje się wiele obiektów tego samego typu (tzw. 'straszliwy diament') i nie używasz dziedziczenia virtual. Może również przejść tylko przez dziedziczenie publiczne - zawsze nie przejdzie przez protected lub private dziedziczenie. Rzadko jest to jednak problemem, gdyż takie formy dziedziczenia są Rzadki.


reinterpret_cast jest najniebezpieczniejszą obsadą i powinna być używana bardzo oszczędnie. Zamienia jeden typ bezpośrednio w inny - na przykład odlewanie wartości z jednego wskaźnika do drugiego lub przechowywanie wskaźnika w int, lub wszelkiego rodzaju inne paskudne rzeczy. W dużej mierze jedyną gwarancją, jaką otrzymujesz z reinterpret_cast, jest to, że normalnie, jeśli oddasz wynik z powrotem do oryginalnego typu, otrzymasz dokładnie tę samą wartość (ale Nie jeżeli Typ pośredni jest mniejszy niż oryginalny typ). Istnieje wiele konwersji, które reinterpret_cast nie da rady. Jest używany przede wszystkim do szczególnie dziwnych konwersji i manipulacji bitami, takich jak przekształcanie nieprzetworzonego strumienia danych w rzeczywiste dane lub przechowywanie danych w niskich bitach wyrównanego wskaźnika.


C-style cast i function-style cast są odlewami za pomocą odpowiednio (type)object lub type(object). Rzut w stylu C jest zdefiniowany jako pierwszy z następujących, który

  • const_cast
  • static_cast (choć ignorując ograniczenia dostępu)
  • static_cast (patrz wyżej), następnie const_cast
  • reinterpret_cast
  • reinterpret_cast, następnie const_cast

Może więc być używany jako zamiennik dla innych odlewów w niektórych przypadkach, ale może być bardzo niebezpieczny ze względu na zdolność przekształcania się w reinterpret_cast, a ten ostatni powinien być preferowany, gdy potrzebne jest wyraźne odlewanie, chyba że jesteś pewien, że static_cast powiedzie się lub reinterpret_cast zawiedzie. Nawet wtedy rozważ dłuższą, bardziej wyraźną opcję.

Odlewy w stylu C ignorują również kontrolę dostępu podczas wykonywania static_cast, co oznacza, że mają możliwość wykonania operacji, której nie może wykonać żaden inny odlewnik. Jest to jednak w większości kludge, a moim zdaniem jest to kolejny powód, aby unikać rzutów w stylu C.

 2255
Author: coppro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-16 08:25:06

Użyj dynamic_cast do konwersji wskaźników / odniesień w hierarchii dziedziczenia.

Użyj static_cast do konwersji zwykłych typów.

Użyj reinterpret_cast do niskopoziomowej reinterpretacji wzorców bitowych. Stosować ze szczególną ostrożnością.

Użyj const_cast do odrzucenia const/volatile. Unikaj tego, chyba że utkniesz przy użyciu niepoprawnego API.

 293
Author: Fred Larson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-04 07:48:17

(Wiele teoretycznych i pojęciowych wyjaśnień zostało podanych powyżej)

Poniżej kilka z praktycznych przykładów kiedy użyłem static_cast, dynamic_cast, const_cast, reinterpret_cast .

(odnosi się również do tego, aby zrozumieć Wyjaśnienie: 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);
}
 160
Author: Sumit Arora,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-11 00:22:00

To może pomóc, jeśli znasz trochę wewnętrznych...

Static_cast

  • kompilator C++ wie już, jak przekonwertować typy skalerów, takie jak float do int. Użyj static_cast dla nich.
  • w ogólnym przypadku konwersji z typu A na B, static_cast wywołanie konstruktora B przekazującego A jako param. Jeśli B nie ma takiego konstruktora, to pojawia się błąd czasu kompilacji.
  • rzut od A* do B* zawsze się powiedzie, jeśli a i B są w dziedziczeniu hierarchia (lub void) w przeciwnym razie dostajesz błąd kompilacji.
  • Gotcha : jeśli rzucisz wskaźnik bazowy na wskaźnik Pochodny, ale jeśli rzeczywisty obiekt nie jest tak naprawdę typem pochodnym, to nie otrzymasz błędu. Masz zły wskaźnik i segfault w czasie wykonywania. To samo dotyczy A& do B&.
  • Gotcha : Cast from Derived to Base or viceversa creates new copy! Dla ludzi wywodzących się z C# / Javy może to być ogromny niespodzianka.

Dynamic_cast

  • dynamic_cast używa informacji typu runtime, aby dowiedzieć się, czy cast jest poprawny. Na przykład, (Base*) do (Derived*) może się nie udać, jeśli wskaźnik nie jest typem pochodnym.
  • oznacza to, że dynamic_cast jest bardzo drogi w porównaniu do static_cast!
  • dla A* do B*, jeśli Cast jest nieprawidłowy, to dynamic_cast zwróci nullptr.
  • For A& to B& if cast is invalid then dynamic_cast will throw bad_cast wyjątek.
  • W przeciwieństwie do innych odlewów, istnieje nadmiarowość runtime.

Const_cast

  • podczas gdy static_cast może wykonywać non-const do const, nie może iść w drugą stronę. Const_cast może działać w obie strony.
  • jednym z przykładów, gdzie jest to przydatne, jest iteracja przez jakiś kontener podobny do set<T>, który zwraca tylko swoje elementy jako const, aby upewnić się, że nie zmienisz jego klucza. Jeśli jednak chcesz zmodyfikować inne elementy obiektu, to powinno być ok. Możesz użyć const_cast, aby usunąć constness.
  • Innym przykładem jest, gdy chcesz zaimplementować T& foo(), a także const T& foo(). Aby uniknąć powielania kodu, możesz zastosować const_cast do zwracania wartości jednej funkcji z drugiej.

Reinterpret_cast

  • to w zasadzie mówi, że pobieramy te bajty w tym miejscu pamięci i traktujemy je jako dany obiekt.
  • na przykład, można załadować 4 bajty float do 4 bajtów int, aby zobaczyć jak bity w float wyglądają na przykład.
  • oczywiście, jeśli dane nie są poprawne dla typu, możesz uzyskać segfault.
  • nie ma nadmiarowego czasu wykonania dla tej obsady.
 57
Author: ShitalShah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-27 04:56:49

Czyto odpowiada na twoje pytanie?

Nigdy nie używałem reinterpret_cast i zastanawiam się, czy wpadanie w sprawę, która tego potrzebuje, nie jest zapachem złego designu. W kodzie bazowym, na którym pracuję dynamic_cast jest często używany. Różnica w stosunku do static_cast polega na tym, że dynamic_cast wykonuje sprawdzanie, które może (bezpieczniejsze) lub nie (więcej kosztów) być tym, czego chcesz (zobacz msdn).

 12
Author: andreas buykx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-04 16:31:31

Oprócz innych odpowiedzi do tej pory, tutaj jest nieoczywisty przykład, gdzie {[2] } nie wystarcza, aby reinterpret_cast było potrzebne. Załóżmy, że istnieje funkcja, która w parametrze wyjściowym zwraca wskaźniki do obiektów różnych klas (które nie mają wspólnej klasy bazowej). Prawdziwym przykładem takiej funkcji jest CoCreateInstance() (Zobacz ostatni parametr, który w rzeczywistości jest void**). Załóżmy, że żądasz określonej klasy obiektu z tej funkcji, więc znasz z góry typ wskaźnika (co często robisz dla obiektów COM). W tym przypadku nie możesz dodać wskaźnika do wskaźnika do void** z static_cast: potrzebujesz reinterpret_cast<void**>(&yourPointer).

W kodzie:

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

Jednak static_cast działa dla prostych wskaźników (nie dla wskaźników do wskaźników), więc powyższy kod można przepisać, aby uniknąć reinterpret_cast (za cenę dodatkowej zmiennej) w następujący sposób:

#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);
 12
Author: Serge Rogatch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-22 10:30:03

Podczas gdy inne odpowiedzi ładnie opisywały wszystkie różnice między odlewami C++, chciałbym dodać krótką notatkę, dlaczego nie powinieneś używać odlewów w stylu C (Type) var i Type(var).

Dla początkujących C++ odlewy w stylu C wyglądają jak operacja superset nad odlewami w C++ (static_cast (), dynamic_cast (), const_cast (), reinterpret_cast ()) i ktoś mógłby preferować je nad odlewami w C++. W rzeczywistości Obsada w stylu C jest superset i krótsza do napisania.

Głównym problemem odlewów w stylu C jest to, że ukrywają prawdziwe intencje obsady. Odlewy w stylu C mogą wykonywać praktycznie wszystkie typy odlewów z normalnie bezpiecznych odlewów wykonanych przez static_cast () i dynamic_cast () do potencjalnie niebezpiecznych odlewów, takich jak const (), gdzie modyfikator const może być usunięty, więc zmienne const mogą być modyfikowane i reinterpret_cast (), które mogą nawet reinterpretować wartości całkowite do wskaźników.

Oto próbka.
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.

Głównym powodem dodania C++ do języka było umożliwienie programista, aby wyjaśnić swoje intencje-dlaczego zamierza to zrobić. Używając odlewów w stylu C, które są doskonale poprawne w C++, sprawiasz, że Twój kod jest mniej czytelny i bardziej podatny na błędy, szczególnie dla innych programistów, którzy nie stworzyli Twojego kodu. Tak więc, aby Twój kod był bardziej czytelny i wyraźny, zawsze powinieneś preferować odlewy w C++ niż odlewy w stylu C.

Oto krótki cytat z książki Bjarne Stroustrupa (autora C++) The C++ Programming Language 4th edition-strona 302.

Ta Obsada w stylu C jest znacznie bardziej niebezpieczna niż nazwane operatory konwersji ponieważ zapis jest trudniejszy do zauważenia w dużym programie, a rodzaj konwersji zamierzony przez programistę nie jest jednoznaczny.

 4
Author: Timmy_A,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-22 11:18:21