Aktualisierung 2015: Oder, wenn Sie die Konvertierungsfähigkeit behalten wollen, indem Sie die (double)obj
Syntax stattdessen die obj.to_double()
Syntax, machen Sie die Konvertierungsfunktion explicit
durch Voranstellen dieses Schlüsselworts. Sie benötigen dann einen expliziten Cast, um die Konvertierung auszulösen. Ich persönlich bevorzuge die .to_double
Syntax, es sei denn, die Umwandlung würde in bool
denn in diesem Fall wird die Umwandlung von if(obj)
auch wenn es sich explicit
und das ist wesentlich besser lesbar als if(obj.to_bool())
meiner Meinung nach.
Lassen Sie den Konvertierungsoperator weg. Er wird auf dem ganzen Weg Probleme verursachen. Haben Sie eine Funktion wie
to_double()
Oder eine ähnliche Funktion, die den Double-Wert zurückgibt, und rufen Sie diese Funktion explizit auf, um einen Double-Wert zu erhalten.
Für das vorliegende Problem gibt es dieses Problem:
obj >= 10
Denken Sie an diesen Ausdruck. Der eingebaute Operator entspricht dem ersten Argument durch eine benutzerdefinierte Konvertierungssequenz für Ihren Typ unter Verwendung des Konvertierungsoperators long double(). Aber Ihre Funktion passt zum zweiten Argument durch eine Standardkonvertierungssequenz von int zu long double (Ganzzahl-zu-Gleitkomma-Konvertierung). Es ist immer zweideutig, wenn es Konvertierungen für zwei Argumente gibt, aber nicht mindestens ein Argument, das besser konvertiert werden kann, während die übrigen Argumente für einen Aufruf nicht schlechter konvertiert werden. In Ihrem Fall passt die eingebaute Funktion besser auf das zweite Argument, aber schlechter auf das erste, während Ihre Funktion besser auf das erste, aber schlechter auf das zweite Argument passt.
Das ist verwirrend, deshalb hier einige Beispiele (Umwandlungen von char in int werden Promotionen genannt, die besser sind als Umwandlungen von char in etwas anderes als int, was eine Konvertierung genannt wird):
void f(int, int);
void f(long, long);
f('a', 'a');
Ruft die erste Version auf. Denn alle Argumente für die erste können besser umgewandelt werden. Auch das Folgende ruft noch die erste auf:
void f(int, long);
void f(long, long);
f('a', 'a');
Denn die erste kann besser umgesetzt werden, und die zweite wird nicht schlechter umgesetzt. Aber das Folgende ist zweideutig :
void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous
In diesem Fall ist es noch interessanter. In der ersten Version wird das erste Argument durch eine exakte Übereinstimmung akzeptiert. Die zweite Version akzeptiert das zweite Argument durch eine exakte Übereinstimmung. Aber beide Versionen akzeptieren ihr anderes Argument nicht mindestens gleich gut. Die erste Version verlangt eine Konvertierung für ihr zweites Argument, während die zweite Version eine Beförderung für ihr Argument verlangt. Obwohl also eine Promotion besser ist als eine Konversion, schlägt der Aufruf der zweiten Version fehl.
Es ist sehr ähnlich wie in Ihrem Fall oben. Auch wenn eine Standardkonvertierungssequenz (Konvertierung von int/float/double nach long double) besser als eine benutzerdefinierte Konvertierungssequenz (Konvertierung von MyClass nach long double), wird Ihre Operatorversion nicht gewählt, weil Ihr anderer Parameter (long double) eine Konvertierung des Arguments erfordert, die schlechter ist als das, was der eingebaute Operator für dieses Argument benötigt (perfekte Übereinstimmung).
Die Auflösung von Überladungen ist in C++ eine komplexe Angelegenheit, so dass man sich unmöglich alle subtilen Regeln dazu merken kann. Aber einen groben Plan zu bekommen, ist durchaus möglich. Ich hoffe, es hilft Ihnen.