Forum: PC-Programmierung C++11: Constructor Wirrwar


von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hi,

ich versuche gerade eine C++11 Wrapper-Classe für eine C-Library (nicht 
von mir) zu schreiben.  Die C-Lib bietet float-Funktionen, und die 
Klasse ist:
1
class Float
2
{
3
public:
4
    ~Float();
5
    Float();
6
    Float (long);
7
    explicit Float (double);
8
9
    Float (const Float&);
10
    const Float& operator= (const Float&);
11
    Float (Float&&) = default;
12
    Float& operator= (Float&&) = default;
13
};

Die C-Lib stellt Initialisierungen aus long und double zur Verfügung, 
und offenbar will man nicht double in integer umwandeln (oder umgekehrt) 
bevor ein Float Objekt konstruiert wird.
1
Float func ()
2
{
3
    Float f;
4
    double x = 3.1e10;
5
    f = x;
6
    return f;
7
}

Gibt dann folgende Warnung für "f = x;":
1
warning: overflow in implicit constant conversion [-Woverflow]
und es wird Konstruktor Float(long) verwendet (seh ich am erzeugten 
Code).

Wie schafft man es, dass Float(double) zur Construction aus double 
verwendet wird?

Noch unverständlicher sind die Fehler, wenn es 'nen Constructor
1
Float(int);
gibt: Fehler für "f = x;"
1
error: converting to 'Float' from initializer list would use explicit constructor 'Float::Float(double)'
Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber 
das ist ein Fehler???  Die genennten Konstruktoren sind alle; 
initializer_list wird noch nichtmal included.

Und es gibt nen Fehler
1
error: initializing argument 1 of 'Float& Float::operator=(Float&&)'
Bei einer Zuweisung kann das Float-Objekt einfach kopieren werden wenn 
die rechte Seite nicht mehr gebraucht wird.

Gleicher Fehler mit "Float& Float::operator= (const Float&&);"

von Wilhelm M. (wimalopaan)


Lesenswert?

Du möchtest eine implizite Typwandlung double -> Float. Dann schalte den 
Typumwandlungs-ctor wieder ein.

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Gibt dann folgende Warnung für "f = x;":warning: overflow in implicit
> constant conversion [-Woverflow]
> und es wird Konstruktor Float(long) verwendet (seh ich am erzeugten
> Code).
>
> Wie schafft man es, dass Float(double) zur Construction aus double
> verwendet wird?

Na du hast doch selbst vorgegeben, dass eine Konvertierung von double 
nur explizit erlaubt ist, von long dagegen auch implizit:

>     Float (long);
>     explicit Float (double);

Du machst hier eine implizite Konvertierung, also bleibt ihm nur der 
Konstruktor, der einen long annimmt.


Johann L. schrieb:
> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
> das ist ein Fehler???

Gleiches Thema: Du hast implizite Konvertierungen von double verboten, 
lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme 
denn tun?

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Du möchtest eine implizite Typwandlung double -> Float. Dann schalte den
> Typumwandlungs-ctor wieder ein.

Das explicit bedeutet doch, dass der Konstructor nur dann genommen wird, 
wenn das argument "double" ist, und sonst nicht.  Und gebau das ist doch 
der Fall?

von Wilhelm M. (wimalopaan)


Lesenswert?

Johann L. schrieb:
> Das explicit bedeutet doch, dass der Konstructor nur dann genommen wird,
> wenn das argument "double" ist, und sonst nicht.  Und gebau das ist doch
> der Fall?

Nein.

in "f = x;" muss der Compiler die rechte Seite nach Float (implizit) 
umwandeln. Und das explicit verhindert genau das.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Johann L. schrieb:
>> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
>> das ist ein Fehler???
>
> Gleiches Thema: Du hast implizite Konvertierungen von double verboten,
> lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme
> denn tun?

Wieso brauche ich eine implizite Konvertierung double wenn das Arhument 
bereits ein double ist?

Was ich haben will:

Für einen double soll Float(double) verwendet werden.

Für einen long (oder andere Integer, die ohne Verlust als long 
darstellbar sind), soll Float(long) verwendet werden.

Für alles andere darf momentan gerne ein Error kommen (außer für Float 
selbst natürlich und const Float& etc.).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Johann L. schrieb:
>> Das explicit bedeutet doch, dass der Konstructor nur dann genommen wird,
>> wenn das argument "double" ist, und sonst nicht.  Und genau das ist doch
>> der Fall?
>
> Nein.
>
> in "f = x;" muss der Compiler die rechte Seite nach Float (implizit)
> umwandeln. Und das explicit verhindert genau das.

Wieso das?

Es gibt einen Constructor Float(double) und es gibt Zuweisungen 
operator=(const Float&) und operator=(Float&&).

Muss ich operator= jetzt auch noch für alle erdenklichen Integer und 
double und float etc. implementieren?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Johann L. schrieb:
> Wiese das?

Nochmal: die rechte Seite ist double. Und Du hast einen 
Kopier/Verschiebungszuweisungs-Op für Float. Also muss(!) der Compiler 
die recht Seite nach Float (implizit) umwandlen. Daher brauchst Du einen 
Typwandlungs-ctor. Den hast Du aber mit explicit ausgeschaltet.

Also entweder:

- nimm das explicit weg (wenn Du das Verhalten haben willst)

oder

- schreib einen passenden Kopierzuweisungs-Op (ggf. auch 
Verschiebungszuweisungs-Op, wenn Du das möchtest).

von Oliver S. (oliverso)


Lesenswert?

Johann L. schrieb:
> Wieso brauche ich eine implizite Konvertierung double wenn das Arhument
> bereits ein double ist?

> Float f;
> double x = 3.1e10;
> f = x;

Die letzte Zeile ist eine Zuweisung, keine Initialisierung, und 
erfordert einen cast von double nach float. Dafür braucht es einen 
cast-operator, der wegen "explicit" nicht verfügbar ist.

Ein
1
Float f{3.1e10};
oder
1
Float f = 3.1e10;

ruft den Konstruktor auf, und funktioniert daher.

Oliver

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Ein
>
1
Float f{3.1e10};
> oder
>
1
Float f = 3.1e10;
>
> ruft den Konstruktor auf, und funktioniert daher.

Mit
1
Float func ()
2
{
3
    Float f = 3.1e10;
4
    return f;
5
}

bekomme ich ohne Float(int) für "Float f = 3.1e10;"
1
warning: overflow in implicit constant conversion [-Woverflow]

und erzeugt wird ein Constructor für long, nicht für double.

Mit Float(int) bekomme ich für "Float f = 3.1e10;"
1
error: conversion from 'double' to 'Float' is ambiguous
2
note: candidates are:
3
note: Float::Float(int)
4
note: Float::Float(long int)

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Rolf M. schrieb:
>> Johann L. schrieb:
>>> Jetzt wird der Konstruktor verwendet, der verwendet werden soll, aber
>>> das ist ein Fehler???
>>
>> Gleiches Thema: Du hast implizite Konvertierungen von double verboten,
>> lässt hier dem Compiler aber keine andere Möglichkeit. Was soll der arme
>> denn tun?
>
> Wieso brauche ich eine implizite Konvertierung double wenn das Arhument
> bereits ein double ist?

Ja, eben. Das Argument ist double:
1
f = x;
Für Zuweisungen hast du nur einen Operator angegeben, der ein Float als 
Argument hat, also muss x erst in ein Float konvertiert werden, damit es 
im Anschluss nach f kopiert werden kann.
Nun gibt es zwei Arten der Konvertierung: Implizit und explizit. 
Implizit heißt, dass es konvertiert wird, ohne dass du ausdrücklich in 
deinem Code den Wunsch dazu äußern musst.
explizit heißt, dass du es angeben musst. Das wäre z.B. so möglich:
1
f = static_cast<Float>(x);

Da du den Konvertierkonstruktor Float(double) als explicit markiert 
hast, hast du damit gesagt, dass diese Konvertierung nur als explizite 
Konvertierung erlaubt ist, also mit einem Cast.

Johann L. schrieb:
> Es gibt einen Constructor Float(double)

Der ist aber als explicit markiert, und damit nimmst du dem Compiler die 
Möglichkeit, den in diesem Fall zu verwenden.

> Muss ich operator= jetzt auch noch für alle erdenklichen Integer und
> double und float etc. implementieren?

Kann man machen, je nachdem.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.