Need Präzisierungen in C-Stil, reinterpret und konst Abgüsse
-
23-09-2019 - |
Frage
Bin ich recht in der Annahme, dass C-Casts (die entmutigt sind) sind nichts anderes als reinterpret_casts? letzteres unter Verwendung von optisch fällt und einfach, wenn für böse Abgüsse und daher wird empfohlen, über C-Casts?
suchen zu suchenWenn Wegwerfen const const_cast verwenden und auf ein ursprünglich konstantes Objekt zu schreiben ist nicht definiert, was ist der Zweck der const_cast?
Hinweis: Ich weiß, dass Bjarne verurteilt zu Recht Gießvorgängen, dass sie unsicher sind und geht sogar soweit, der besagt, „Ein hässlich Operation sollte eine hässliche syntaktische Form hat. " und damit die Ausführlichkeit der Operatoren in C ++ Gießen. Also werde ich versuchen, ihre Nutzung zu minimieren. Versprechen. :)
Lösung
Nein. A C Guss kann die äquivalent einen const_cast
tun, ein static_cast
, ein reinterpret_cast
oder eine Kombination davon. Im Fall, dass nicht genug war, kann es auch mindestens einen Moll-Trick, dass nicht Kombination des neueren Abgüsse überhaupt tun kann!
Sie können const_cast
mit definierten Ergebnis zu erzielen, wenn die ursprüngliche Variable ohne const
definiert ist, aber alles, was Sie haben, ist ein const
Zeiger oder eine Referenz auf das Objekt. OTOH, wenn Sie denken, Sie haben einen guten Grund eine const_cast
zu verwenden, stehen die Chancen, dass Sie wirklich statt mutable
aussehen sollte.
Edit: Ich glaube, ich sollte es weg vom Recht gesagt haben, aber ein C-Casts kann zu einer unzugänglichen Basisklasse konvertieren. Betrachten wir zum Beispiel so etwas wie:
[Edit: Ich bin Aktualisierung des Code auf etwas, das kompilieren werden und (in der Regel) demonstriert Problem. ]
#include <iostream>
class base1 {
public:
virtual void print() { std::cout << "base 1\n"; }
};
class base2 {
public:
virtual void print() { std::cout << "base 2\n"; }
};
class derived : base1, base2 {}; // note: private inheritance
int main() {
derived *d = new derived;
base1 *b1 = (base1 *)d; // allowed
b1->print(); // prints "base 1"
base2 *b2 = (base2 *)d; // also allowed
b2->print(); // prints "base 2"
// base1 *bb1 = static_cast<base *>(d); // not allowed: base is inaccessible
// Using `reinterpret_cast` allows the code to compile.
// Unfortunately the result is different, and normally won't work.
base1 *bb2 = reinterpret_cast<base1 *>(d);
bb2->print(); // may cause nasal demons.
base2 *bb3 = reinterpret_cast<base2 *>(d);
bb3->print(); // likewise
return 0;
}
Der Code der reinterpret_cast
s mit kompiliert - aber versuchen, das Ergebnis zu verwenden (zumin damit einer der beiden) wird ein großes Problem verursachen. Die reinterpret_cast
nimmt die Basis Adresse des abgeleiteten Objekts und versucht, sie zu behandeln, als ob es die angegebene Art von Basisobjekt war - und da (höchstens) ein Basisobjekt kann an dieser Adresse tatsächlich existiert, versuchen, es wie die andere Dose zu behandeln / wird zu großen Problemen führen. Edit: In diesem Fall sind die Klassen im Wesentlichen identisch mit der Ausnahme, was sie drucken, so dass, obwohl alles könnte passieren, mit den meisten Compilern, die beide der letzten beiden druckt out „Basis 1“. Die reinterpret_cast nimmt, was an dieser Adresse und versucht zu sein geschieht es mit dem angegebenen Typ zu verwenden. In diesem Fall habe ich (versucht) machen, die etwas harmlos tun, aber sichtbar. In echtem Code, wird das Ergebnis wahrscheinlich nicht so schön sein.
Der C-Casts wird wie ein static_cast arbeiten würde, wenn der Code öffentliche Vererbung benutzt hatte, statt privat - das heißt, es ist bekannt, wo in der abgeleiteten Klasse jede Basisklasse Objekt „lebt“, und stellt das Ergebnis, so dass jeder resultierende Zeiger funktionieren werden, weil es an der richtigen Stelle.
Punkt eingestellt ist schonAndere Tipps
Nein, C-Casts können als reinterpret_cast
s, const-cast
s oder static_cast
s wirken auf die Situation abhängig. Aus diesem Grund ist sie entmutigt sind - Sie einen C-Casts in Code und müssen schauen Details siehe, um zu sehen, was es tun wird. Zum Beispiel:
const char* source;
int* target = (int*)source;// - acts as const_cast and reinterpret_cast at once
//int* target = retinterpret_cast<int*>source;// - won't compile - can't remove const
Denken Sie daran, dass eine konstante Besetzung auf etwas anderes handeln kann dann die ursprüngliche Kennung:
void doit(const std::string &cs)
{
std::string &ms = const_cast<std::string &>(cs);
}
int main()
{
std::string s;
doit(s);
}
Während also doit wirft weg const, in diesem Beispiel die zugrunde liegenden Zeichenfolge ist nicht const so kein undefiniertes Verhalten.
Aktualisieren
Okay, hier ist ein besseres Beispiel, wenn const_cast verwendet, ist nicht völlig wertlos. Wir beginnen mit einer Basisklasse mit einer virtuellen Funktion, die einen const Parameter annimmt:
class base
{
public:
virtual void doit(const std::string &str);
};
und jetzt wollen Sie diese virtuelle Funktion außer Kraft zu setzen.
class child : public base
{
public:
virtual void doit(const std::string &str)
{
std::string &mstr = const_cast<std::string &>(str);
}
};
Aufgrund der Logik / Struktur des Codes, wissen Sie, dass child::doit
nur mit nicht konstanten Strings aufgerufen werden (und class base
ist unter Ihrer Kontrolle nicht, so dass Sie es nicht ändern können, noch können Sie die Unterschrift von child::doit
ändern, weil dann wird es nicht mehr überschreiben base::doit
). In diesem Fall ist es sicher konst wegzuwerfen.
Ja, das ist riskant. Vielleicht, wenn Sie schreiben, dass, es ist wahr, dass die Ausführung nie child::doit
mit einem nicht-const string erreichen und der Code gültig ist. Aber das könnte entweder ändern, während Ihr Programm beibehalten oder vielleicht, wenn Sie wieder aufzubauen und die neueste Version von class base
abholen.
const_cast
verwendet const
von einem Typ zu entfernen. Es kann auch volatile
entfernen. Wenn das Objekt wirklich const
wird, dann kann das Ergebnis nicht zu und noch Verhalten gut definiert werden, geschrieben werden. Wenn jedoch wird es zu const
gefördert (indem sie in eine const T
Funktion übergeben wird, dann ist es const_cast
ing zurück zu nicht-const
ist in Ordnung. (I ein paar mehr Infos gefunden hier )
reinterpret_cast
kann nicht Entfernen const
oder volatile
von einem Typ.
C-Casts sind wirklich der Hammer Schlitten der Programmierung - Sie grundsätzlich den Compiler sagen, dass die quadratischen Pflock dort durch dieses runde Loch passt, egal was. In diesem Sinne ist reinterpret_cast
sehr ähnlich.
Der Hauptvorteil ich bei der Verwendung der C ++ sehen - Casts Operatoren sind, dass sie ermöglichen es Ihnen, Ihre Absicht besser auszudrücken und dem Compiler noch über den Betrieb bis zu einem gewissen Kontrolle ermöglicht es Ihnen, es sind gefragt ein- bis ausführen, anstatt size-fits-all-Stil C gegossen.
In Bezug auf const_cast
- Sie oft in die Situation kommen, wo Sie ein Objekt um über konstante Referenz einfach sind vorbei, da die API Sie erfordert dies zu tun. Sag mal, du hast Funktion X bekam, dass die Aufgaben einer C-String:
void X(const char *str) { ... }
Im Inneren, die Sie funktionieren vorbei sind die Parameter an eine C-Funktion, die eine char *
erwartet, auch wenn die Zeichenfolge nicht ändert sich. Der einzige Weg, dies zu unterbringen zu const_cast
str sein würde.
würde ich sehr vorsichtig sein, jede Art von Besetzung mit, oft dies zeigt, dass es etwas nicht ganz richtig mit Ihrem Design ist aber manchmal muss man die Compiler davon überzeugen, dass der Stift an es sieht nicht so quadratisch wie es annimmt, . Erst dann sollten Sie die Cast-Operatoren verwenden.