web-dev-qa-db-fra.com

Opérateurs de conversion en C ++

Veuillez m'aider à comprendre comment fonctionnent exactement les opérateurs de conversion en C++. J'ai un exemple simple ici que j'essaie de comprendre, bien qu'il ne soit pas très clair comment la conversion se produit réellement par le compilateur.

class Example{
public:
    Example();
    Example(int val);
    operator unsigned int();
    ~Example(){}
private:
    int itsVal;
};

Example::Example():itsVal(0){}

Example::Example(int val):itsVal(val){}

Example::operator unsigned int (){
    return (itsVal);
}

int main(){
    int theInt = 5;
    Example exObject = theInt; // here 
    Example ctr(5);
    int theInt1 = ctr; // here
    return 0;
}
28
Zuzu

Vous pouvez parcourir ce code avec un débogueur (et/ou mettre un point d'arrêt sur chacun de vos constructeurs et opérateurs) pour voir lequel de vos constructeurs et opérateurs est appelé par quelles lignes.

Parce que vous ne les avez pas définis explicitement, le compilateur a également créé un constructeur de copie caché/par défaut et un opérateur d'affectation pour votre classe. Vous pouvez les définir explicitement (comme suit) si vous souhaitez utiliser un débogueur pour voir où/quand ils sont appelés.

Example::Example(const Example& rhs)
: itsVal(rhs.itsVal)
{}

Example& operator=(const Example& rhs)
{
    if (this != &rhs)
    {
        this->itsVal = rhs.itsVal;
    }
    return *this;
}
9
ChrisW
int main() {
    int theInt = 5;

    /**
     * Constructor "Example(int val)" in effect at the statement below.
     * Same as "Example exObject(theInt);" or "Example exObject = Example(theInt);"
     */
    Example exObject = theInt; // 1

    Example ctr(5);

    /**
     * "operator unsigned int()" in effect at the statement below.
     * What gets assigned is the value returned by "operator unsigned int()".
     */
    int theInt1 = ctr; // 2

    return 0;
}

À l'instruction 1, le constructeur Example(int val) est appelé. Déclarez-le comme explicit Example(int val) et vous obtiendrez une erreur de temps de compilation, c'est-à-dire qu'aucune conversion implicite ne sera alors autorisée pour ce constructeur.

Tous les constructeurs d'arguments uniques sont appelés implicitement si la valeur affectée est de leur type d'argument respectif. L'utilisation du mot clé explicit avant les constructeurs à argument unique désactive l'appel implicite du constructeur et donc la conversion implicite.

Si le constructeur était déclaré explicite, c'est-à-dire explicit Example(int val), alors ce qui se passerait pour chaque instruction.

Example exObject(theInt); // Compile time error.
Example exObject = theInt; // Compile time error.
Example exObject(Example(theInt)); // Okay!
Example exObject = Example(theInt); // Okay!

Notez également qu'en cas d'appel de constructeur implicite et donc de conversion implicite, la valeur attribuée est une valeur r, c'est-à-dire un objet sans nom créé implicitement à l'aide d'une valeur l (theInt) qui nous indique qu'en cas de conversion implicite, le compilateur convertit

Example exObject = theInt;

à

Example exObject = Example(theInt);

Donc (en C++ 11) ne vous attendez pas à ce que le constructeur lvalue soit appelé vu que vous utilisez une lvalue, c'est-à-dire une valeur nommée theInt pour l'affectation. Ce qui est appelé est le constructeur rvalue puisque la valeur assignée est en fait l'objet sans nom créé à l'aide de lvalue. Toutefois, cela s'applique si vous disposez à la fois des versions lvalue et rvalue du constructeur.

À l'instruction 2 operator unsigned int() est appelée. Considérez-le simplement comme un appel de fonction normal avec un nom étrange et le fait qu'il peut être appelé automatiquement par une conversion implicite. La valeur renvoyée par cette fonction est la valeur affectée dans l'expression. Et comme dans votre implémentation, la valeur renvoyée est un entier correctement affecté à int theInt1.

Pour être précis, operator unsigned int() surcharge l'opérateur () Qui est l'opérateur de transtypage. Dans votre cas, il est surchargé pour int donc chaque fois qu'un objet de la classe Example est assigné à un int le transtypage de type implicite de Example vers int a lieu et donc operator unsigned int() est appelé. Par conséquent,

int theInt1 = ctr;

est équivalent à

int theInt1 = (int)ctr;
5
Mubeen Iqbal
Example exObject = theInt; // implicitly created copy constructor takes place
// object implicitly created from int and then copied
// it is like
Example exObject = Example(theInt);
// so it uses sequence
// Example(int) -> Example(const Example&)
int theInt1 = ctr; // operator int()

Si votre compilateur prend en charge l'optimisation du constructeur de copie et l'optimisation de la valeur de retour, vous ne le remarquerez pas

Example(const Example&)

exécution, mais vous pouvez déclarer que le constructeur de copie est privé pour comprendre de quoi je parle.

4
Mykola Golubyev
Example exObject = theInt; // here

Cela utilise la conversion implicite de int en Example, effectuée par le constructeur non explicite qui accepte un int.

Cela nécessite également la disponibilité du constructeur de copie pour l'exemple, même si le compilateur est autorisé à omettre de copier l'instance.

int theInt1 = ctr; // here

Cela utilise la conversion implicite de Example en entier non signé, fournie par l'opérateur de conversion.

Les opérateurs de transtypage sont normalement évités, car ils entraînent généralement une confusion dans le code et vous pouvez marquer explicitement les constructeurs à argument unique pour désactiver les conversions implicites de votre type de classe. C++ 0x devrait également ajouter la possibilité de marquer les opérateurs de conversion comme explicites (vous auriez donc besoin d'un static_cast pour les invoquer? - mon compilateur ne les prend pas en charge et toutes les ressources Web semblent se concentrer sur la conversion explicite en bool).

2
UncleBens