Benutzerdefinierte Konvertierungsfunktion
Ermöglicht implizite Konvertierung oder explizite Konvertierung von einem Klassentyp in einen anderen Typ.
Inhalt |
[bearbeiten] Syntax
Eine Konvertierungsfunktion wird wie eine nicht-statische Memberfunktion oder eine Member-Funktionstemplate ohne Parameter, ohne expliziten Rückgabetyp und mit dem Namen der Form deklariert
operator conversion-type-id |
(1) | ||||||||
explicit operator conversion-type-id |
(2) | (seit C++11) | |||||||
explicit ( expression ) operator conversion-type-id |
(3) | (seit C++20) | |||||||
conversion-type-id ist ein type-id, mit der Ausnahme, dass Funktions- und Array-Operatoren [] oder () in seinem Deklarator nicht zulässig sind (daher erfordert die Konvertierung in Typen wie Zeiger auf Array einen Typ-Alias/typedef oder ein Identitätstemplate: siehe unten). Unabhängig von typedef kann conversion-type-id keinen Array- oder Funktionstyp darstellen.
Obwohl der Rückgabetyp in der Deklaration einer benutzerdefinierten Konvertierungsfunktion nicht zulässig ist, kann die decl-specifier-seq der Deklarationsgrammatik vorhanden sein und neben type-specifier oder dem Schlüsselwort static jede Spezifikation enthalten. Insbesondere neben explicit sind auch die Spezifikationen inline, virtual, constexpr(seit C++11), consteval(seit C++20) und friend zulässig (beachten Sie, dass friend einen qualifizierten Namen erfordert: friend A::operator B();).
Wenn eine solche Memberfunktion in der Klasse X deklariert wird, führt sie eine Konvertierung von X in conversion-type-id durch.
struct X { // implicit conversion operator int() const { return 7; } // explicit conversion explicit operator int*() const { return nullptr; } // Error: array operator not allowed in conversion-type-id // operator int(*)[3]() const { return nullptr; } using arr_t = int[3]; operator arr_t*() const { return nullptr; } // OK if done through typedef // operator arr_t () const; // Error: conversion to array not allowed in any case }; int main() { X x; int n = static_cast<int>(x); // OK: sets n to 7 int m = x; // OK: sets m to 7 int* p = static_cast<int*>(x); // OK: sets p to null // int* q = x; // Error: no implicit conversion int (*pa)[3] = x; // OK }
[bearbeiten] Erklärung
Die benutzerdefinierte Konvertierungsfunktion wird in der zweiten Stufe der impliziten Konvertierung aufgerufen, die aus null oder einem Konstruktor oder null oder einer benutzerdefinierten Konvertierungsfunktion besteht.
Wenn sowohl Konvertierungsfunktionen als auch Konvertierungskonstruktoren für eine benutzerdefinierte Konvertierung verwendet werden können, werden die Konvertierungsfunktionen und Konstruktoren bei der Überladungsauflösung in Kontexten der Kopierinitialisierung und Referenzinitialisierung berücksichtigt, aber in Kontexten der direkten Initialisierung werden nur die Konstruktoren berücksichtigt.
struct To { To() = default; To(const struct From&) {} // converting constructor }; struct From { operator To() const {return To();} // conversion function }; int main() { From f; To t1(f); // direct-initialization: calls the constructor // Note: if converting constructor is not available, implicit copy constructor // will be selected, and conversion function will be called to prepare its argument // To t2 = f; // copy-initialization: ambiguous // Note: if conversion function is from a non-const type, e.g. // From::operator To();, it will be selected instead of the ctor in this case To t3 = static_cast<To>(f); // direct-initialization: calls the constructor const To& r = f; // reference-initialization: ambiguous }
Konvertierungsfunktionen in die eigene (möglicherweise cv-qualifizierte) Klasse (oder eine Referenz darauf), in die Basisklasse der eigenen Klasse (oder eine Referenz darauf) und in den Typ void können definiert werden, aber nicht als Teil der Konvertierungssequenz ausgeführt werden, außer in einigen Fällen durch virtuelle Weiterleitung.
struct D; struct B { virtual operator D() = 0; }; struct D : B { operator D() override { return D(); } }; int main() { D obj; D obj2 = obj; // does not call D::operator D() B& br = obj; D obj3 = br; // calls D::operator D() through virtual dispatch }
Sie kann auch über die Memberfunktionsaufrufsyntax aufgerufen werden.
struct B {}; struct X : B { operator B&() { return *this; }; }; int main() { X x; B& b1 = x; // does not call X::operatorB&() B& b2 = static_cast<B&>(x); // does not call X::operatorB& B& b3 = x.operator B&(); // calls X::operatorB& }
Beim expliziten Aufruf der Konvertierungsfunktion ist conversion-type-id "gierig": Es ist die längste Zeichenfolge, die potenziell eine conversion-type-id bilden kann (einschließlich Attribute, falls vorhanden)(seit C++11).
& x.operator int * a; // error: parsed as & (x.operator int*) a, // not as & (x.operator int) * a operator int [[noreturn]] (); // error: noreturn attribute applied to a type
|
Der Platzhalter auto kann in conversion-type-id verwendet werden, was einen abgeleiteten Rückgabetyp angibt. struct X { operator int(); // OK operator auto() -> short; // error: trailing return type not part of syntax operator auto() const { return 10; } // OK: deduced return type operator decltype(auto)() const { return 10l; } // OK: deduced return type }; Hinweis: Eine Konvertierungsfunktionstemplate darf keinen abgeleiteten Rückgabetyp haben. |
(seit C++14) |
Konvertierungsfunktionen können geerbt werden und virtuell sein, aber nicht statisch. Eine Konvertierungsfunktion in der abgeleiteten Klasse verbirgt keine Konvertierungsfunktion in der Basisklasse, es sei denn, sie konvertieren in denselben Typ.
Eine Konvertierungsfunktion kann eine Template-Memberfunktion sein, z. B. std::auto_ptr<T>::operator auto_ptr<Y>. Siehe Member-Templates und Template-Argument-Deduktion für anwendbare Sonderregeln.
[bearbeiten] Schlüsselwörter
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 296 | C++98 | Konvertierungsfunktionen könnten statisch sein | sie können nicht als statisch deklariert werden |
| CWG 2016 | C++98 | Konvertierungsfunktionen konnten keine Rückgabetypen angeben, aber die Typen sind in conversion-type-id vorhanden |
Rückgabetypen können nicht in den Deklarationsspezifikationen von Konvertierungsfunktionen |
| CWG 2175 | C++11 | war es unklar, ob die [[noreturn]] in operator int [[noreturn]] (); als Teil von noptr-declarator (eines Funktionsdeklarators) oder conversion-type-id geparst wird |
es wird als Teil von conversion-type-id |