29 votes

Objets pouvant être initialisés mais non affectés

J'ai besoin de créer une classe dont les objets peuvent être initialisés mais non assignés.

J'ai pensé que je pourrais peut-être le faire en ne définissant pas l'opérateur d'affectation, mais le compilateur utilise le constructeur pour effectuer l'affectation.

J'ai besoin que ce soit comme ça:

 Object a=1;    // OK
a=1;           // Error
 

Comment puis-je le faire?

58voto

Yousaf Points 4563

Rendant a const fera l'affaire

const Object a=1;    // OK

Maintenant, vous ne serez pas en mesure d'attribuer de la valeur à a comme a est déclaré en tant que const. Notez que si vous déclarez a comme const, il est nécessaire d'initialiser a au moment de la déclaration.

Une fois que vous avez déclarée a comme const et également initialisé, vous ne serez pas en mesure d'affecter n'importe quelle autre valeur de a

 a=1;   //error

49voto

Jonas Points 5829

Vous pouvez supprimer l'opérateur d'affectation:

#include <iostream>
using namespace std;

struct Object
{
    Object(int) {}
    Object& operator=(int) = delete;
};

int main()
{
    Object a=1;    // OK
    a=1;           // Error
}

Solution Alternative

Vous pouvez utiliser l' explicite mot-clé:

#include <iostream>
using namespace std;

struct Object
{
    explicit Object(int) {}
};

int main()
{
    Object a(1);    // OK - Uses explicit constructor
    a=1;           // Error
}

Mise à jour

Comme mentionné par user2079303 dans les commentaires:

Il pourrait être utile de mentionner que la solution de rechange n'empêche pas régulier copier/déplacer assignation comme a=Object(1)

Ceci peut être évité en utilisant: Object& operator=(const Object&) = delete;

13voto

songyuanyao Points 2265

J'espérais que ce serait donc, en ne définissant pas l'opérateur d'affectation

Cela ne fonctionne pas car la copie opérateur d'affectation (qui prend en const Object& comme paramètre) est implicitement généré. Et quand vous écrivez a = 1, à la génération de copie opérateur d'affectation ne sera tenté d'invoquer, et 1 pourrait être implicitement converti en Object via la conversion de constructeur Object::Object(int); ensuite, a = 1; fonctionne très bien.

Vous pouvez déclarer l'opérateur d'affectation en prenant int comme supprimé (depuis C++11) de façon explicite; qui sera choisi avant la copie opérateur d'assignation en résolution de surcharge.

Si la fonction est surchargé, la résolution de surcharge a lieu en premier, et le programme n'est mal formé, si l'supprimé la fonction a été sélectionnée.

par exemple

struct Object {
    Object(int) {}
    Object& operator=(int) = delete;
};

Il y a aussi d'autres solutions avec des effets secondaires. Vous pouvez déclarer Object::Object(int) comme explicit à interdire la conversion implicite de int de Object puis faire de l' a = 1 échouer. Mais notez que cela rendra Object a = 1; aussi échouer parce que la copie de l'initialisation de ne pas envisager explicit constructeur. Ou vous pouvez marquer l'opérateur d'assignation de copie supprimé trop, mais cela permettra de rendre la cession entre Objects aussi échouer.

9voto

R Sahu Points 24027

Comment puis-je le faire?

Option 1:

Faire le constructeur explicit

struct Object
{
   explicit Object(int in) {}
};

Option 2:

delete de l'opérateur d'affectation.

struct Object
{
   Object(int in) {}
   Object& operator=(int in) = delete;
};

Vous pouvez utiliser les deux options ci-dessus.

struct Object
{
   explicit Object(int in) {}
   Object& operator=(int in) = delete;
};

Option 3:

Si vous ne voulez pas de cession après l'initialisation, vous pouvez delete de l'opérateur d'affectation avec Object comme type d'argument.

struct Object
{
   explicit Object(int in) {}
   Object& operator=(Object const& in) = delete;
};

Pour empêcher toute utilisation de:

Object a(1);
a = Object(2); // Error
a = 2;         // Error

7voto

Mrnell Points 91

Supprimé les fonctions sont disponibles uniquement à partir de C++11, pour les anciens compilateurs, vous pouvez procéder à la cession de l'opérateur private.

struct Object
{
Object(int) {}
private: 
Object& operator=(int);
};

Compilateur va maintenant lancer d'erreur pour

Object a=1; //ok
a=2; // error 

Mais vous pouvez toujours le faire

Object a=1,b=2;
b=a;

Parce que l'affectation par défaut de l'opérateur n'est pas empêché d'être générés par le compilateur. Afin de marquage par défaut private permettra de résoudre cette question.

struct Object
{
Object(int) {}
private: 
Object& operator=(Object&);
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X