Regulärer Cast vs. static_cast vs. dynamic_cast [duplicate]

Lesezeit: 12 Minuten

Regularer Cast vs static cast vs dynamic cast duplicate
Graem Perrow

Ich schreibe seit fast zwanzig Jahren C- und C++-Code, aber es gibt einen Aspekt dieser Sprachen, den ich nie wirklich verstanden habe. Ich habe offensichtlich normale Besetzungen verwendet, dh

MyClass *m = (MyClass *)ptr;

überall, aber es scheint zwei andere Arten von Besetzungen zu geben, und ich kenne den Unterschied nicht. Was ist der Unterschied zwischen den folgenden Codezeilen?

MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);

  • Ich würde die Umwandlung im alten C-Stil in C++ nicht als “regulären Cast” bezeichnen, da es alles andere als ist. Sie sollten C++ im Allgemeinen nicht verwenden, insbesondere bei Klassen, da es einfach zu leicht ist, Fehler damit zu machen. Die Verwendung davon ist ein Zeichen für einen C-Programmierer, der zu C++ gewechselt ist, aber C++ noch nicht ganz gelernt hat.

    – Hyde

    30. Januar 2013 um 7:03 Uhr


  • Wie kann eine Frage mit Antwort ein Duplikat einer Frage ohne Antwort sein? mehr noch, diese Frage wurde früher gestellt als das “Original”

    – Wladp

    21. Juni 2015 um 8:28 Uhr


  • @Vladp Falls Sie sich immer noch fragen oder jemand anderes dies liest und sich wundert. (Außerdem, fürs Protokoll, es war kein Moderator, der dies geschlossen hat, sondern ein Benutzer mit einem Dupe-Hammer)

    – Nik

    1. Februar 2017 um 1:16 Uhr


  • Zu Ihrer Information, die verknüpfte Frage hat viel mehr positive Stimmen und die Antworten haben auch viel mehr positive Stimmen. Auch die verknüpfte Frage enthält einige gute nicht-theoretische Beispiele. (Außerdem bezieht sich die verknüpfte Frage nicht fälschlicherweise auf die Typumwandlungssyntax im C-Stil als “reguläre Umwandlung”.)

    – Trevor Boyd Smith

    7. März 2018 um 14:20 Uhr


Regularer Cast vs static cast vs dynamic cast duplicate
Johannes Schaub – litb

static_cast

`static_cast` wird für Fälle verwendet, in denen Sie grundsätzlich eine implizite Konvertierung mit einigen Einschränkungen und Ergänzungen rückgängig machen möchten. `static_cast` führt keine Laufzeitprüfungen durch. Dies sollte verwendet werden, wenn Sie wissen, dass Sie sich auf ein Objekt eines bestimmten Typs beziehen und somit eine Überprüfung unnötig wäre. Beispiel:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

In diesem Beispiel wissen Sie, dass Sie a bestanden haben MyClass -Objekt, und daher ist keine Laufzeitprüfung erforderlich, um dies sicherzustellen.

dynamic_cast

`dynamic_cast` ist nützlich, wenn Sie den dynamischen Typ des Objekts nicht kennen. Es gibt einen Null-Zeiger zurück, wenn das Objekt, auf das verwiesen wird, nicht den Typ enthält, in den als Basisklasse gecastet wurde (wenn Sie in eine Referenz umwandeln, wird in diesem Fall eine ‘bad_cast’-Ausnahme ausgelöst).

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

Sie können nicht verwenden dynamic_cast wenn Sie downcasten (in eine abgeleitete Klasse umwandeln) und der Argumenttyp nicht polymorph ist. Der folgende Code ist beispielsweise nicht gültig, weil Base enthält keine virtuelle Funktion:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

Ein “up-cast” (cast auf die Basisklasse) ist immer bei beiden gültig static_cast und dynamic_castund auch ohne Cast, da ein “up-cast” eine implizite Konvertierung ist (vorausgesetzt, die Basisklasse ist zugänglich, dh es ist eine public Nachlass).

Normale Besetzung

Diese Casts werden auch als C-Style Cast bezeichnet. Eine Umwandlung im C-Stil ist im Grunde identisch mit dem Ausprobieren einer Reihe von Sequenzen von C++-Umwandlungen und dem Nehmen der ersten C++-Umwandlung, die funktioniert, ohne jemals darüber nachzudenken dynamic_cast. Unnötig zu erwähnen, dass dies viel leistungsfähiger ist, da es alle kombiniert const_cast, static_cast und reinterpret_castaber es ist auch unsicher, weil es nicht verwendet wird dynamic_cast.

Darüber hinaus können Sie mit C-Style-Casts nicht nur dies tun, sondern auch sicher in eine private Basisklasse umwandeln, während das “Äquivalent” static_cast Sequenz würde Ihnen dafür einen Kompilierzeitfehler geben.

Einige Leute bevorzugen wegen ihrer Kürze C-Style-Casts. Ich verwende sie nur für numerische Umwandlungen und verwende die entsprechenden C++-Umwandlungen, wenn benutzerdefinierte Typen beteiligt sind, da sie eine strengere Prüfung bieten.

  • Siehe auch die beiden zusätzlichen Casts von boost: boost.org/doc/libs/1_47_0/libs/conversion/…

    – Neil G

    10. August 2011 um 17:31 Uhr

  • @JohannesSchaub-litb: Sind Sie sicher, dass Sie mit einer Umwandlung im C-Stil „sicher“ in eine private Basisklasse umwandeln können? Ich kann sehen, dass das funktioniert, wenn die private Basisklasse die einzige /base/ ist, aber was ist mit virtueller/mehrfacher Vererbung? Ich gehe davon aus, dass die Besetzung im C-Stil keine Zeigermanipulation durchführt.

    – Josef Garwin

    29. Februar 2012 um 18:32 Uhr

  • @JohannesSchaub-litb Stimmt es, dass die Verwendung der alten C-Style-Casts gegenüber den C++-Casts auch einen gewissen Overhead mit sich bringt?

    – xcrypt

    10. Mai 2012 um 19:47 Uhr

  • @Joseph: Es wird kein Crosscast korrekt durchgeführt oder in einem der anderen Fälle, in denen eine Laufzeitprüfung erforderlich ist (dynamic_cast ist nötig). Aber es werden alle die gleichen Zeigeranpassungen wie static_cast tut. Mehrfache (nicht-virtuelle) Vererbung wird problemlos unterstützt, und die korrekte Zeigereinstellung wird verwendet.

    – Ben Voigt

    28. Dezember 2012 um 21:16 Uhr

  • Können Sie genauer erklären, warum der Downcast im dynamischen Besetzungsabschnitt ungültig ist? davon ausgehen Derived hatte ein member m Ich möchte erreichen, wie würde dies erreicht werden, wenn dynamic_cast ist keine Option?

    – ted

    9. März 2013 um 0:06 Uhr

Statische Besetzung

Die statische Umwandlung führt Konvertierungen zwischen kompatiblen Typen durch. Sie ähnelt der Besetzung im C-Stil, ist jedoch restriktiver. Zum Beispiel würde die Umwandlung im C-Stil einem Integer-Zeiger erlauben, auf ein Zeichen zu zeigen.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Da dies zu einem 4-Byte-Zeiger führt, der auf 1 Byte des zugewiesenen Speichers zeigt, wird das Schreiben in diesen Zeiger entweder einen Laufzeitfehler verursachen oder angrenzenden Speicher überschreiben.

*p = 5; // run-time error: stack corruption

Im Gegensatz zur Umwandlung im C-Stil ermöglicht die statische Umwandlung dem Compiler, zu überprüfen, ob die Datentypen von Zeiger und Pointee kompatibel sind, wodurch der Programmierer diese falsche Zeigerzuweisung während der Kompilierung abfangen kann.

int *q = static_cast<int*>(&c); // compile-time error

Besetzung neu interpretieren

Um die Zeigerkonvertierung zu erzwingen, würde stattdessen die Umwandlung im C-Stil auf die gleiche Weise wie die Umwandlung im C-Stil im Hintergrund verwendet werden.

int *r = reinterpret_cast<int*>(&c); // forced conversion

Diese Umwandlung verarbeitet Konvertierungen zwischen bestimmten nicht verwandten Typen, z. B. von einem Zeigertyp zu einem anderen inkompatiblen Zeigertyp. Es führt einfach eine binäre Kopie der Daten aus, ohne das zugrunde liegende Bitmuster zu verändern. Beachten Sie, dass das Ergebnis einer solchen Low-Level-Operation systemspezifisch und daher nicht portierbar ist. Es sollte mit Vorsicht angewendet werden, wenn es nicht ganz vermieden werden kann.

Dynamische Besetzung

Dieser wird nur verwendet, um Objektzeiger und Objektreferenzen in andere Zeiger- oder Referenztypen in der Vererbungshierarchie umzuwandeln. Es ist die einzige Umwandlung, die sicherstellt, dass das Objekt, auf das gezeigt wird, konvertiert werden kann, indem eine Laufzeitprüfung durchgeführt wird, dass der Zeiger auf ein vollständiges Objekt des Zieltyps verweist. Damit diese Laufzeitprüfung möglich ist, muss das Objekt polymorph sein. Das heißt, die Klasse muss mindestens eine virtuelle Funktion definieren oder erben. Dies liegt daran, dass der Compiler nur die erforderlichen Laufzeittypinformationen für solche Objekte generiert.

Dynamische Besetzungsbeispiele

Im folgenden Beispiel a MyChild Zeiger wird in a umgewandelt MyBase Zeiger mit dynamischer Umwandlung. Diese Ableitung-zu-Basis-Konvertierung ist erfolgreich, da das untergeordnete Objekt ein vollständiges Basisobjekt enthält.

class MyBase 
{ 
  public:
  virtual void test() {}
};
class MyChild : public MyBase {};



int main()
{
  MyChild *child = new MyChild();
  MyBase  *base = dynamic_cast<MyBase*>(child); // ok
}

Das nächste Beispiel versucht, a zu konvertieren MyBase Zeiger auf a MyChild Zeiger. Da das Basisobjekt kein vollständiges untergeordnetes Objekt enthält, schlägt diese Zeigerkonvertierung fehl. Um dies anzuzeigen, gibt die dynamische Umwandlung einen Nullzeiger zurück. Auf diese Weise kann zur Laufzeit bequem überprüft werden, ob eine Konvertierung erfolgreich war oder nicht.

MyBase  *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);

 
if (child == 0) 
std::cout << "Null pointer returned";

Wenn anstelle eines Zeigers eine Referenz konvertiert wird, schlägt die dynamische Umwandlung fehl, indem a geworfen wird bad_cast Ausnahme. Dies muss mit a behandelt werden try-catch Aussage.

#include <exception>
// …  
try
{ 
  MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e) 
{ 
  std::cout << e.what(); // bad dynamic_cast
}

Dynamischer oder statischer Cast

Der Vorteil der Verwendung eines dynamischen Casts besteht darin, dass der Programmierer während der Laufzeit überprüfen kann, ob eine Konvertierung erfolgreich war oder nicht. Der Nachteil besteht darin, dass mit dieser Prüfung ein Leistungsaufwand verbunden ist. Aus diesem Grund wäre im ersten Beispiel die Verwendung eines statischen Casts vorzuziehen gewesen, da eine Konvertierung von abgeleitet nach Basis niemals fehlschlagen wird.

MyBase *base = static_cast<MyBase*>(child); // ok

Im zweiten Beispiel kann die Konvertierung jedoch entweder erfolgreich sein oder fehlschlagen. Es wird scheitern, wenn die MyBase Objekt enthält a MyBase Instanz und es wird erfolgreich sein, wenn es eine enthält MyChild Beispiel. In einigen Situationen kann dies bis zur Laufzeit nicht bekannt sein. In diesem Fall ist die dynamische Umwandlung die bessere Wahl als die statische Umwandlung.

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

Wenn die Basis-zu-abgeleitete-Konvertierung unter Verwendung einer statischen Umwandlung anstelle einer dynamischen Umwandlung durchgeführt worden wäre, wäre die Umwandlung nicht fehlgeschlagen. Es hätte einen Zeiger zurückgegeben, der auf ein unvollständiges Objekt verweist. Das Dereferenzieren eines solchen Zeigers kann zu Laufzeitfehlern führen.

// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
 
// Incomplete MyChild object dereferenced
(*child);

Konstante Besetzung

Dieser wird hauptsächlich verwendet, um die hinzuzufügen oder zu entfernen const Modifikator einer Variablen.

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

Obwohl const cast ermöglicht es, den Wert einer Konstante zu ändern, dies ist jedoch immer noch ungültiger Code, der einen Laufzeitfehler verursachen kann. Dies könnte beispielsweise auftreten, wenn sich die Konstante in einem Abschnitt des Nur-Lese-Speichers befindet.

*nonConst = 10; // potential run-time error

const cast wird stattdessen hauptsächlich verwendet, wenn es eine Funktion gibt, die ein nicht konstantes Zeigerargument akzeptiert, obwohl es den Pointee nicht ändert.

void print(int *p) 
{
   std::cout << *p;
}

Der Funktion kann dann mit a eine konstante Variable übergeben werden const Gießen.

print(&myConst); // error: cannot convert 
                 // const int* to int*
 
print(nonConst); // allowed

Quelle und weitere Erläuterungen

  • std::bad_cast ist darin definiert <typeinfo>

    – Evg

    17. April 2017 um 17:19 Uhr


  • vom Kind zur Basis, Gips ist nicht erforderlich: MyBase *base = child; // ok

    – Isidoro Ghezzi

    7. September 2018 um 10:07 Uhr


  • Meiner Meinung nach die beste Antwort, sehr einfach und doch klar

    – Mohammed Nureldin

    22. Juli 2019 um 8:21 Uhr

  • das sollte wirklich die Top-Antwort imo sein

    – Jazzig

    5. Mai 2021 um 5:43 Uhr


1647255014 760 Regularer Cast vs static cast vs dynamic cast duplicate
TJ Seabrooks

Du solltest dir den Artikel anschauen C++-Programmierung/Type Casting.

Es enthält eine gute Beschreibung aller verschiedenen Besetzungstypen. Folgendes aus obigem Link:

const_cast

const_cast(expression) const_cast<>() wird verwendet, um const(ness) (oder volatile-ness) einer Variablen hinzuzufügen/zu entfernen.

static_cast

static_cast(expression) Der static_cast<>() wird verwendet, um zwischen den Integer-Typen umzuwandeln. ‘eg’ char->long, int->short usw.

Die statische Umwandlung wird auch verwendet, um Zeiger auf verwandte Typen umzuwandeln, z. B. das Umwandeln von void* in den entsprechenden Typ.

dynamic_cast

Die dynamische Umwandlung wird verwendet, um Zeiger und Referenzen zur Laufzeit umzuwandeln, im Allgemeinen zum Zwecke des Castings eines Zeigers oder einer Referenz nach oben oder unten in einer Vererbungskette (Vererbungshierarchie).

dynamic_cast(ausdruck)

Der Zieltyp muss ein Zeiger- oder Verweistyp sein, und der Ausdruck muss zu einem Zeiger oder Verweis ausgewertet werden. Die dynamische Umwandlung funktioniert nur, wenn der Objekttyp, auf den sich der Ausdruck bezieht, mit dem Zieltyp kompatibel ist und die Basisklasse über mindestens eine virtuelle Elementfunktion verfügt. Wenn dies nicht der Fall ist und der Typ des umgewandelten Ausdrucks ein Zeiger ist, wird NULL zurückgegeben. Wenn eine dynamische Umwandlung einer Referenz fehlschlägt, wird eine bad_cast-Ausnahme ausgelöst. Wenn dies nicht fehlschlägt, gibt die dynamische Umwandlung einen Zeiger oder eine Referenz des Zieltyps auf das Objekt zurück, auf das der Ausdruck verwiesen hat.

reinterpret_cast

Reinterpret cast wandelt einfach einen Typ bitweise in einen anderen um. Jeder Zeiger oder integrale Typ kann mit Reinterpret Cast in einen anderen umgewandelt werden, was leicht einen Missbrauch ermöglicht. Zum Beispiel könnte man mit reinterpret cast einen Integer-Zeiger auf unsichere Weise in einen String-Zeiger umwandeln.

1647255015 888 Regularer Cast vs static cast vs dynamic cast duplicate
Jason Baker

Zu Ihrer Information, ich glaube, Bjarne Stroustrup wird mit den Worten zitiert, dass Umwandlungen im C-Stil vermieden werden sollten und dass Sie nach Möglichkeit static_cast oder dynamic_cast verwenden sollten.

Barne Stroustrups häufig gestellte Fragen zum C++-Stil

Nehmen Sie diesen Rat an, was Sie wollen. Ich bin weit davon entfernt, ein C++-Guru zu sein.

Regularer Cast vs static cast vs dynamic cast duplicate
ugasoft

Vermeiden Sie die Verwendung von C-Style-Casts.

Casts im C-Stil sind eine Mischung aus const und reinterpret cast, und es ist schwierig, sie in Ihrem Code zu finden und zu ersetzen. Ein C++-Anwendungsprogrammierer sollte eine Umwandlung im C-Stil vermeiden.

1647255015 189 Regularer Cast vs static cast vs dynamic cast duplicate
DrPizza

Umwandlungen im C-Stil führen const_cast, static_cast und reinterpret_cast zusammen.

Ich wünschte, C++ hätte keine Umwandlungen im C-Stil. C++-Casts heben sich richtig ab (wie sie es sollten; Casts weisen normalerweise auf etwas Schlechtes hin) und unterscheiden richtig zwischen den verschiedenen Arten von Konvertierungen, die Casts durchführen. Sie erlauben auch, ähnlich aussehende Funktionen zu schreiben, zB boost::lexical_cast, was aus Konsistenzsicht ganz nett ist.

dynamic_cast unterstützt nur Zeiger- und Referenztypen. Es kehrt zurück NULL wenn die Umwandlung nicht möglich ist, wenn der Typ ein Zeiger ist, oder eine Ausnahme auslöst, wenn der Typ ein Referenztyp ist. Somit, dynamic_cast kann verwendet werden, um zu überprüfen, ob ein Objekt von einem bestimmten Typ ist, static_cast nicht (Sie werden einfach mit einem ungültigen Wert enden).

Besetzungen im C-Stil (und andere) wurden in den anderen Antworten behandelt.

  • Sie erhalten einfach einen ungültigen Wert” und ein undefiniertes Verhalten. Das heißt, das Programm hat sich falsch verhalten, auch wenn Sie den Wert nicht verwenden

    – Neugieriger

    3. November 2019 um 0:39 Uhr

1001180cookie-checkRegulärer Cast vs. static_cast vs. dynamic_cast [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy