3158 Stimmen

Wann sollten static_cast, dynamic_cast, const_cast und reinterpret_cast verwendet werden?

Was sind die richtigen Verwendungszwecke von:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C-Stil Guss (type)value
  • Guss im Funktionsstil type(value)

Wie kann man entscheiden, welche in welchen Fällen verwendet werden sollen?

4 Stimmen

Einige nützliche konkrete Beispiele für die Verwendung verschiedener Arten von Gussformen finden Sie in der ersten Antwort auf eine ähnliche Frage in dieses andere Thema .

5 Stimmen

Sie können oben wirklich gute Antworten auf Ihre Frage finden. Aber ich möchte hier noch einen weiteren Punkt anbringen, @e.James "Es gibt nichts, was diese neuen C++ Cast-Operatoren tun können und C Style Cast nicht. Sie sind mehr oder weniger für die bessere Lesbarkeit des Codes hinzugefügt worden."

18voto

andreas buykx Punkte 12236

Hat este Ihre Frage beantworten?

Ich habe nie benutzt reinterpret_cast und fragen sich, ob es nicht nach schlechtem Design riecht, wenn man auf einen Fall stößt, der es braucht. In der Codebasis, an der ich arbeite dynamic_cast wird häufig verwendet. Der Unterschied zu static_cast ist, dass ein dynamic_cast führt eine Laufzeitprüfung durch, die (sicherer) oder nicht (mehr Aufwand) das sein kann, was Sie wollen (siehe msdn ).

5 Stimmen

Ich habe reintrepret_cast für einen Zweck verwendet - immer die Bits aus einem Double (gleiche Größe wie Long Long auf meiner Plattform).

3 Stimmen

Reinterpret_cast wird z.B. für die Arbeit mit COM-Objekten benötigt. CoCreateInstance() hat einen Ausgabeparameter vom Typ void** (der letzte Parameter), in dem Sie Ihren Zeiger übergeben, der z.B. als "INetFwPolicy2* pNetFwPolicy2" deklariert ist. Um das zu tun, müssen Sie etwas wie reinterpret_cast<void**>(&pNetFwPolicy2) schreiben.

2 Stimmen

Vielleicht gibt es einen anderen Ansatz, aber ich verwende reinterpret_cast um Teile von Daten aus einem Array zu extrahieren. Wenn ich zum Beispiel ein char* die einen großen Puffer voller gepackter Binärdaten enthält, die ich durchlaufen muss, um einzelne Primitive unterschiedlicher Typen zu erhalten. Etwas wie dies: template<class ValType> unsigned int readValFromAddress(char* addr, ValType& val) { /*On platforms other than x86(_64) this could do unaligned reads, which could be bad*/ val = (*(reinterpret_cast<ValType*>(addr))); return sizeof(ValType); }

18voto

Serge Rogatch Punkte 12301

Zusätzlich zu den bisherigen Antworten hier noch ein nicht offensichtliches Beispiel, bei dem static_cast nicht ausreichend ist, so dass reinterpret_cast erforderlich ist. Angenommen, es gibt eine Funktion, die in einem Ausgabeparameter Zeiger auf Objekte verschiedener Klassen (die keine gemeinsame Basisklasse haben) zurückgibt. Ein reales Beispiel für eine solche Funktion ist CoCreateInstance() (siehe den letzten Parameter, der in Wirklichkeit void** ). Angenommen, Sie fordern von dieser Funktion eine bestimmte Objektklasse an, so dass Sie im Voraus den Typ des Zeigers kennen (was bei COM-Objekten häufig der Fall ist). In diesem Fall können Sie den Zeiger auf Ihren Zeiger nicht in void** con static_cast : Sie benötigen reinterpret_cast<void**>(&yourPointer) .

Im Code:

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

Allerdings, static_cast funktioniert bei einfachen Zeigern (nicht bei Zeigern auf Zeiger), so dass der obige Code umgeschrieben werden kann, um die reinterpret_cast (zum Preis einer zusätzlichen Variablen) auf folgende Weise:

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

1 Stimmen

Würde es nicht etwa so funktionieren &static_cast<void*>(pNetFwPolicy2) anstelle von static_cast<void**>(&pNetFwPolicy2) ?

15voto

Timmy_A Punkte 962

Während andere Antworten alle Unterschiede zwischen C++-Casts sehr schön beschrieben haben, möchte ich eine kurze Anmerkung hinzufügen, warum Sie keine Casts im Stil von C verwenden sollten (Type) var y Type(var) .

Für C++-Anfänger sehen C-Style-Casts so aus, als wären sie die Obermenge der C++-Casts (static_cast<>(), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()), und jemand könnte sie den C++-Casts vorziehen. In der Tat ist C-style cast die Obermenge und kürzer zu schreiben.

Das Hauptproblem von C-Güssen ist, dass sie die eigentliche Absicht des Entwicklers verbergen. Die Casts im C-Stil können praktisch alle Arten von Casts durchführen, von normalerweise sicheren Casts wie static_cast<>() und dynamic_cast<>() bis hin zu potenziell gefährlichen Casts wie const_cast<>(), bei denen der const-Modifikator entfernt werden kann, so dass die const-Variablen geändert werden können, und reinterpret_cast<>(), das sogar Integer-Werte in Zeiger uminterpretieren kann.

Hier ist das Beispiel.

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.

Der Hauptgrund, warum C++ Casts in die Sprache aufgenommen hat, war, dass ein Entwickler seine Absichten verdeutlichen kann - warum er diesen Cast durchführen wird. Durch die Verwendung von Casts im Stil von C, die in C++ durchaus zulässig sind, machen Sie Ihren Code weniger lesbar und fehleranfälliger, insbesondere für andere Entwickler, die Ihren Code nicht erstellt haben. Um Ihren Code also lesbarer und eindeutiger zu machen, sollten Sie immer C++-Casts gegenüber C-Stil-Casts bevorzugen.

Hier ist ein kurzes Zitat aus Bjarne Stroustrups (dem Autor von C++) Buch The C++ Programming Language 4th edition - Seite 302.

Dieser Cast im C-Stil ist weitaus gefährlicher als die genannten Konvertierungsoperatoren weil die Notation in einem großen Programm schwerer zu erkennen ist und die vom Programmierer beabsichtigte Art der Umwandlung nicht explizit ist.

1 Stimmen

Hochstufung aufgrund des Verweises auf Stroustrups Zitat. Schwer zu finden in diesen Tagen, vor allem, dass wir oft stattdessen hörte es von sehr schlau Menschen und nicht der Mann selbst.

6voto

pkthapa Punkte 979

Um dies zu verstehen, betrachten wir das folgende Codeschnipsel:

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

Nur Zeile (4) lässt sich ohne Fehler kompilieren. Nur uminterpretieren_gießen kann verwendet werden, um einen Zeiger auf ein Objekt in einen Zeiger auf einen beliebigen, nicht verwandten Objekttyp umzuwandeln.

Eines ist zu beachten: Die dynamisch_gecastet würde zur Laufzeit scheitern, aber auf den meisten Compilern wird es auch nicht kompiliert werden können, weil es keine virtuellen Funktionen in der Struktur des Zeigers gibt, der gecastet wird, was bedeutet dynamisch_gecastet funktioniert nur mit polymorphen Klassenzeigern.

Wann wird ein C++-Cast verwendet? :

  • Utilice statisch_gecastet als Äquivalent zu einem Cast im C-Stil, der eine Wertkonvertierung vornimmt, oder wenn wir einen Zeiger explizit von einer Klasse zu ihrer Oberklasse hochcasten müssen.
  • Utilice const_cast um den const-Bezeichner zu entfernen.
  • Utilice uminterpretieren_gießen um unsichere Konvertierungen von Zeigertypen in und aus Ganzzahlen und anderen Zeigertypen durchzuführen. Verwenden Sie dies nur, wenn Sie wissen, was Sie tun, und die Aliasing-Problematik verstehen.

0 Stimmen

Das bereitgestellte Snippet ist ein schlechtes Beispiel. Ich stimme zwar zu, dass es in der Tat kompiliert. Die Wenn Die Auflistung ist zwar vage korrekt, enthält aber größtenteils Meinungen, die nicht ausreichen, um die erforderliche Granularität zu ergründen.

1voto

Adrian Punkte 875

Nettes Merkmal von reinterpret_cast die in den anderen Antworten nicht erwähnt wurde, ist, dass es uns ermöglicht, eine Art von void* Zeiger für Funktionstypen. Normalerweise verwendet man für Objekttypen static_cast um den ursprünglichen Typ eines Zeigers abzurufen, der in void* :

  int i = 13;
  void *p = &i;
  auto *pi = static_cast<int*>(p);

Für Funktionen müssen wir reinterpret_cast zweimal:

#include<iostream>

using any_fcn_ptr_t = void(*)();

void print(int i)
{
   std::cout << i <<std::endl;
}

int main()
{     
  //Create type-erased pointer to function:
  auto any_ptr = reinterpret_cast<any_fcn_ptr_t>(&print);

  //Retrieve the original pointer:
  auto ptr = reinterpret_cast< void(*)(int) >(any_ptr);

  ptr(7);
}

Mit reinterpret_cast können wir sogar eine ähnliche Art von Void*-Zeiger für Zeiger auf Mitgliedsfunktionen erhalten.

Wie bei einfachen void* y static_cast garantiert C++, dass ptr zeigt auf print Funktion (solange wir den richtigen Typ an reinterpret_cast ).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X