Autre moyen d'interdire une certaine construction de classe C ++, sauf que de déclarer le constructeur privé?

StackOverflow https://stackoverflow.com/questions/7317530

  •  26-10-2019
  •  | 
  •  

Question

Dire que j'ai une classe avec une référence const variable membre et je voudrais interdire à un certain type de construction. Donc je déclarerais le constructeur selon private . Bien sûr, un constructeur doit initialiser tous référence const variables membres de la classe. Cela, cependant, les résultats dans le code à la recherche étrange:

class A {
};

class B {
  B(const A& a): host(a) {}
private:
  B():host(A()) {}   // This is ugly and not needed !!
  const A& host;
};

Y at-il une autre façon d'interdire à un certain type de construction, sauf que de déclarer le constructeur privé? Je ne veux pas laisser l'écriture du compilateur un constructeur pour moi.

Était-ce utile?

La solution

Il suffit de ne pas définir ceci:

B():host(A()) {}   // This is ugly and not needed !!

C'est, ce qui suit devrait faire ce que vous voulez faire:

class B {
  B(const A& a): host(a) {}
private:
  //B():host(A()) {}   // This is ugly and not needed !!
  const A& host;
};

L'idée est que si vous avez défini un constructeur qui prend paramètre (s), le constructeur par défaut n'est pas généré par le compilateur. Cela signifie, les instances de la classe ci-dessus ne peuvent pas de default créé!

 B b1; //error - needs default constructor which doesn't exist!
 B b2(a); //ok - only way to create an instance!

C ++ 11 solution

En C ++ 11, vous pouvez dire au compilateur Explicity de ne pas générer un constructeur particulier:

struct B
{
     B(const A &a) {}

     B() = delete;      //disable
};

Non seulement cela. Il y a plus à lui, comme expliqué ci-dessous:

Maintenant la partie intéressante

Vous pouvez également désactiver de manière sélective constructeur (s) pour sélectionnés types qui rend delete plus intéressant. Considérez ceci,

struct A
{
       A (int) {}
};

Objet de cette classe peut être créé non seulement avec l'argument de int, mais tout type qui implicitement convertis à int. Par exemple,

A a1(10);  //ok
A a2('x'); //ok - char can convert to int implicitly

B b; 
A a3(b); //ok - assume b provides user-defined conversion to int

Supposons maintenant, pour une raison quelconque, je ne veux pas que les utilisateurs de A de classe pour créer des objets avec char ou class B, qui, heureusement, ou malheureusement peut implicitement Convertir en int, vous pouvez les désactiver comme suit:

struct A
{
     A(int) {}
     A(char) = delete;      //disable
     A(const B&) = delete;  //disable
};

Vous allez:

A a1(10);  //ok
A a2('x'); //error

B b; 
A a3(b); //error - assume (even if) b provides user-defined conversion to int

Démo en ligne: http://ideone.com/EQl5R

Les messages d'erreur sont très claires:

prog.cpp: 9: 5: Erreur: fonction supprimée 'A :: A (char)'
prog.cpp: 10: 5: Erreur: fonction supprimée 'A :: A (const B &)'

Autres conseils

Il suffit de le laisser sortir. Dès que vous fournissez un constructeur personnalisé, aucun autre constructeur est généré automatiquement (sauf pour un constructeur de copie).

Si vous voulez interdire tout la construction - de se retrouver avec une classe qui ne dispose que des membres statiques - vous pouvez simplement déclarer le constructeur comme privé, et non définir il. Une telle classe est très rarement utile en C ++ (puisque vous ne pouvez pas créer des instances de celui-ci); le seul but que je peux penser est de mettre en œuvre des classes trait:

template <typename T>
struct type_to_color {
    static char const* value() { return "blue"; }

private:
    type_to_color();
};

template <>
struct type_to_color<int> {
    // Integers are red!
    static char const* value() { return "red"; }

private:
    type_to_color();
}

char const* char_color = type_to_color<char>::value();
char const* int_color  = type_to_color<int>::value();

Cependant, ce qui est extrêmement rare. Trait des classes sont abondantes en C ++, mais ils ne déclarent leurs constructeurs comme private, il est juste supposé que tout le monde ne sait pas les instancier

Je posterai le C ++ 11 solution:. Supprimer le constructeur

class B {
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};

Comme Konrad Rudolph sayd: que vous fournissez bientôt un constructeur personnalisé, aucun autre constructeur est généré automatiquement (sauf pour un constructeur de copie)

.

Par conséquent, d'autres options sont:

Déclarez le constructeur privé (de sorte que vous ne pouvez pas hériter de votre classe), mais ne fournit pas une définition:

class B {
public:
  B(const A& a): host(a) {}
private:
  B(); // not implemented!
  const A& host;
};

Ou en C ++ 11, comme le dit R. Martinho Fernandes:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top