Diese Situation steht im Zusammenhang mit How to Machen Sie eine Einschränkung für die Parameter des Konstruktors , aber es ist etwas anders.
Sie möchten ein nicht standardkonstruktives Member initialisieren, müssen jedoch vor dem Erstellen nach Constraints suchen.
(Bitte beachten Sie, dass dies nur ein Beispiel ist. Ob in dieser speziellen Situation nicht ganzzahlige Ganzzahlen verwendet werden sollen, ist diskussionswürdig, aber die Frage betrifft den allgemeinen Fall, in dem Sie Konstruktoren einchecken möchten)
Sie haben die folgende Klasse:
%Vor%Der Konstruktor muss die Ganzzahlargumente auf Gültigkeit prüfen:
%Vor% Beachten Sie, dass Buffer
keinen Standardkonstruktor hat und der wahre Konstruktor noexcept
ist, d. h. es gibt keine Möglichkeit, einen Fehler zu finden.
Wenn die Integer-Argumente negativ sind, hat man bereits surface_
abgesprungen. Es wäre schöner, die Bedingung zu überprüfen vor mit dem eingeschränkten Wert. Ist es möglich?
Sie können einen sogenannten benannten Konstruktor verwenden (siehe auch Ссылка ), und machen Sie den Konstruktor private
:
Benannte Konstruktoren sind interessant, falls Sie mehrere Konstruktoren haben, die möglicherweise nicht eindeutig zu verwenden sind, z. Temperatur & lt; - Celsius | Fahrenheit | Kelvin oder Entfernung & lt; - Meter | Hof | Cubit | Kilometer ... .
Andernfalls (persönliche Meinung) erzwingen sie eine unerwartete Abstraktion und auch Ablenkung und sollten vermieden werden.
throw
C ++ erlaubt in [expr.cond] die Verwendung von throw
-Ausdrücken in einem oder beiden Operanden für den ternären Operator ( ?:
-operator):
Wenn Sie die Argumente nicht speichern, können Sie natürlich auch ?:
in einem Ausdruck verwenden:
Oder Sie kombinieren die Vorbedingungsprüfung in einen einzelnen Operanden:
%Vor% Die Verwendung des ?:
-Operators mit einem throw
-Ausdruck inline kann sehr nützlich für die Überprüfung grundlegender Integritätsregeln sein und vermeidet die Verwendung eines Standardkonstruktors (falls vorhanden) und dann "echte Initialisierung" innerhalb des Konstruktor-Körpers.
Dies kann für komplexere Szenarien ein wenig unhandlich werden.
Das Beste aus beiden Welten kann natürlich verwendet werden:
%Vor%... oder Sie schreiben statische Funktionen für jedes Element, das Sie vorkonditionieren müssen:
%Vor%Das ist nett, weil Sie die komplette C ++ - Maschinerie zur Verfügung haben, um die Constraint-Überprüfung durchzuführen, und zum Beispiel einfach Logging hinzufügen können. Es skaliert gut, ist aber für einfache Szenarien ein wenig weniger praktisch.
Lösung von phresnel mit inline throw
und dem Vorschlag in Curgs Antwort zur Verwendung vorzeichenloser Ganzzahlen weist beide auf eine allgemeine Lösung hin: Verwenden von Typen, um sicherzustellen, dass die Werte durch Konstruktion korrekt sind.
Wenn Breite und Höhe nicht negativ sein können, empfiehlt es sich, sie ohne Vorzeichen zu erstellen. Wenn jedoch eine maximale Grenze vorhanden ist, benötigen Sie möglicherweise einen präziseren Typ zum Angeben der Invarianten, z. B .:
%Vor%Dann könnten Sie sagen:
%Vor% Aber dann möchten Sie möglicherweise erzwingen, dass die Breite und Höhe ein Seitenverhältnis nicht größer als 16: 9 haben. Sie können sie also in einem Size
-Typ bündeln und so weiter. Auf diese Weise wurde die gesamte Validierungslogik für die Mitglieder von RenderTarget
zu dem Zeitpunkt ausgeführt, an dem der Konstruktorkörper beginnt.
Diese Art der Kapselung ist grundlegend für die objektorientierte Programmierung: Die öffentliche Schnittstelle eines Objekts kann nicht verwendet werden, um sie in einen ungültigen Zustand zu versetzen, und der Konstruktor ist Teil der öffentlichen Schnittstelle.
Es gibt auch die Möglichkeit, das Problem zu vereinfachen, indem Größe, Höhe und Breite ohne Vorzeichen gemacht werden, was verhindert, dass jemals ein negativer Zustand eintritt.
%Vor%Der Konstruktor muss die Ganzzahlargumente auf Gültigkeit prüfen:
%Vor%Zusätzliche Fehlerbehandlung:
Wenn die Verwendung des Typs zum Einschränken ungültiger Werte nicht ausreicht, gibt es viele bewährte Möglichkeiten zum Behandeln von Fehlersituationen, die über das Auslösen von Ausnahmen hinausgehen, wie zum Beispiel:
%Vor%oder
%Vor%oder
%Vor%oder ...
Viele andere Alternativen.
Es gibt Vor- und Nachteile für jeden Ansatz zur Validierung von Daten, aber ich empfehle generell, die Lösung einfach genug zu halten, um sie wartbar und lesbar zu halten, da diese Lösungen oft überentwickelt werden können.
Tags und Links c++ initialization constraints initialization-list