Ich komme hauptsächlich aus Python und habe Probleme mit der Arbeit mit Typen in C ++.
Ich versuche, eine Klassenvariable über einen von mehreren überladenen Konstruktoren zu initialisieren, die verschiedene Typen als Parameter verwenden. Ich habe gelesen, dass die Verwendung des auto
Schlüsselworts für die automatische Deklaration einer Variablen verwendet werden kann. In meinem Fall wird sie jedoch erst initialisiert, wenn ein Konstruktor ausgewählt wird. Der Compiler ist jedoch nicht glücklich darüber, dass er nicht initialisiert wird value
.
class Token {
public:
auto value;
Token(int ivalue) {
value = ivalue;
}
Token(float fvalue) {
value = fvalue;
}
Token(std::string svalue) {
value = svalue;
}
void printValue() {
std::cout << "The token value is: " << value << std::endl;
}
};
In Python könnte dies so aussehen:
class Token():
def __init__(self, value):
self.value = value
def printValue(self):
print("The token value is: %s" % self.value)
Wie wird das auto
Schlüsselwort in diesem Szenario richtig verwendet ? Sollte ich einen anderen Ansatz wählen?
auto
für Klassenmitglieder verwenden? Relevante, aber veraltete Frage: Ist es möglich, eine "automatische" Mitgliedsvariable zu haben?Antworten:
In C ++ gibt es keine "Variable unbekannten Typs".
Automatisch abgeleitete Variablen haben einen Typ, der vom Initialisierer abgeleitet wird. Wenn kein Initialisierer vorhanden ist, können Sie auto nicht verwenden. auto kann nicht für eine nicht statische Elementvariable verwendet werden. Eine Instanz einer Klasse kann keine anders typisierten Mitglieder haben als eine andere Instanz.
In diesem Szenario gibt es keine Möglichkeit, das Schlüsselwort auto zu verwenden.
Wahrscheinlich. Es sieht so aus, als würden Sie versuchen, a zu implementieren
std::variant
. Wenn Sie eine Variable zum Speichern eines von X Typen benötigen, sollten Sie diese verwenden.Möglicherweise versuchen Sie jedoch, die dynamische Eingabe in C ++ zu emulieren. Obwohl es Ihnen aufgrund der Erfahrung mit Python vielleicht vertraut ist, ist dies in vielen Fällen nicht der ideale Ansatz. In diesem speziellen Beispielprogramm müssen Sie beispielsweise nur die Mitgliedsvariable drucken. Es wäre also einfacher, jeweils einen String zu speichern. Andere Ansätze sind statischer Polymorphismus, wie er von Rhathin gezeigt wird, oder dynamischer Polymorphismus im OOP-Stil, wie er von Fire Lancer gezeigt wird.
quelle
union
ist ein fehleranfälliger Low-Level-Mechanismus.variant
verwendet es wahrscheinlich intern und macht seine Verwendung sicherer.variant
tut Gebrauchunion
. Die Alternative, bei der Rohspeicher und Platzierung neu verwendet werden, kann in einemconstexpr
Konstruktor nicht verwendet werden .C ++ ist eine statisch typisierte Sprache , dh alle Variablentypen werden vor der Laufzeit festgelegt. Daher ist das
auto
Schlüsselwort keinvar
Schlüsselwort in Javascript, einer dynamisch typisierten Sprache.auto
Das Schlüsselwort wird häufig verwendet, um Typen anzugeben, die unnötig komplex sind.Was Sie suchen, können Sie stattdessen mit der C ++ - Vorlagenklasse tun, mit der Sie mehrere Versionen der Klasse erstellen können, die unterschiedliche Typen annehmen.
Dieser Code könnte die Antwort sein, nach der Sie suchen.
Dieser Code wird kompiliert, wenn einige Bedingungen erfüllt sind, z. B. sollte die Funktion
operator<<
für std :: ostream & und Typ T definiert werden.quelle
Ein anderer Ansatz als der, den andere vorgeschlagen haben, ist die Verwendung von Vorlagen. Hier ist ein Beispiel:
Dann können Sie Ihre Klasse folgendermaßen verwenden:
quelle
Sie können den
std::variant
Typ verwenden. Der folgende Code zeigt einen Weg (aber es ist ein bisschen ungeschickt, muss ich zugeben):Es wäre viel schöner, wenn das
std::get<0>(value)
so geschrieben werden könnte,std::get<value.index()>(value)
aber leider muss das "x" in<x>
ein konstanter Ausdruck zur Kompilierungszeit sein.quelle
std::visit
alsswitch
.auto
muss auf einen bestimmten Typ ableitbar sein, bietet keine dynamische Typisierung zur Laufzeit.Wenn Sie zum Zeitpunkt der Deklaration
Token
alle möglichen Typen kennen, die Sie verwenden könnenstd::variant<Type1, Type2, Type3>
usw. Dies ähnelt einer "Typaufzählung" und einer "Vereinigung". Es stellt sicher, dass die richtigen Konstruktoren und Destruktoren aufgerufen werden.Eine Alternative könnte darin bestehen,
Token
für jeden Fall einen anderen Subtyp (möglicherweise unter Verwendung von Vorlagen) mit geeigneten virtuellen Methoden zu erstellen .quelle
Die folgende Lösung ähnelt im Geiste der Antwort von Fire Lancer. Der Hauptunterschied besteht darin, dass der Kommentar möglicherweise mithilfe von Vorlagen verfolgt wird und somit keine explizit erstellten abgeleiteten Instanzen der Schnittstelle mehr erforderlich sind.
Token
ist nicht selbst die Schnittstellenklasse. Stattdessen wird die Schnittstelle als innere Klasse und als innere Vorlagenklasse definiert, um die Definition der abgeleiteten Klassen zu automatisieren.Die Definition erscheint zu komplex. Allerdings
Token::Base
definiert die Schnittstelle undToken::Impl<>
leitet sich von der Grenzfläche. Diese inneren Klassen sind dem Benutzer von vollständig verborgenToken
. Die Verwendung würde wie folgt aussehen:Die folgende Lösung zeigt auch, wie ein Konvertierungsoperator implementiert werden kann, um
Token
einer regulären Variablen eine Instanz zuzuweisen . Es stützt sich aufdynamic_cast
und löst eine Ausnahme aus, wenn die Besetzung ungültig ist.Die Definition von
Token
ist unten.Probieren Sie es online aus!
quelle