¿Otra forma de prohibir una cierta construcción de la clase C ++, excepto que declara el constructor privado?

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

  •  26-10-2019
  •  | 
  •  

Pregunta

Di que tengo una clase con algunos referencia constante Variable de miembro y me gustaría prohibir un cierto tipo de construcción. Entonces declararía el constructor según privado. Por supuesto, un constructor debe inicializar todo referencia constante Variables de miembros de la clase. Hacerlo, sin embargo, resulta en código de aspecto impar:

class A {
};

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

¿Hay otra forma de prohibir un cierto tipo de construcción, excepto declarar el constructor privado? No quiero dejar que el compilador escriba un constructor para mí.

¿Fue útil?

Solución

Simplemente no defina esto:

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

Es decir, lo siguiente debe hacer lo que quiere hacer:

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

La idea es que si ha definido un constructor que toma (s) parámetros (s), entonces el compilador no genera el constructor predeterminado. Eso significa, instancias de la clase anterior no poder ser defecto ¡creado!

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

Solución C ++ 11

En C ++ 11, puede explicarle al compilador que no genere un constructor particular como:

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

     B() = delete;      //disable
};

No solo eso. Hay más, como se explica a continuación:

Ahora la parte interesante

También puede deshabilitar selectivamente los constructores para seleccionado tipos que hacen delete más interesante. Considera esto,

struct A
{
       A (int) {}
};

El objeto de esta clase se puede crear no solo con int argumento, pero cualquier tipo que se convierta implícitamente en int. Por ejemplo,

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

Ahora suponga que, por cualquier razón, no quiero que los usuarios de la clase A para crear objetos con char o class B , que afortunadamente o desafortunadamente puede implícitamente convertir a int, entonces puedes deshabilitarlos como:

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

Ahora aquí vas:

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

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

Demostración en línea: http://ideone.com/eql5r

Los mensajes de error están muy claros:

prog.cpp: 9: 5: error: función eliminada 'a :: a (char)'
prog.cpp: 10: 5: error: función eliminada 'a :: a (const b &)'

Otros consejos

Solo déjalo afuera. Tan pronto como proporcione un constructor personalizado, ningún otro constructor se genere automáticamente (excepto un constructor de copias).

Si quieres prohibir ningún Construcción: termina con una clase que solo tiene miembros estáticos, simplemente puede declarar el constructor como privado, y no definir eso. Tal clase rara vez es muy útil en C ++ (ya que no puede crear instancias de ella); El único propósito que puedo pensar es implementar clases de rasgos:

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();

Sin embargo, esto es extremadamente raro: las clases de rasgos son abundantes en C ++, pero nunca declaran a sus constructores como private, se supone que todos saben que no deben instanciarlos.

Publicaré la solución C ++ 11: Eliminar el constructor.

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

Como Konrad Rudolph Sayd: tan pronto como proporciona un constructor personalizado, ningún otro constructor se genere automáticamente (excepto un constructor de copias).

Por lo tanto, otras opciones son:

Declare el constructor privado (para que no pueda heredar de su clase), pero no proporcione una definición:

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

O en C ++ 11, como dice R. Martinho Fernandes:

class B {
public:
  B() = delete;
  B(const A& a): host(a) {}
private:
  const A& host;
};
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top