with initialize enclosed brace argument c++ initialization-list

c++ - initialize - Inicializar const variables miembro



c++ initialize class with parameters (4)

Puedes usar el constructor delegado en C ++ 11:

class Foo{ public: Foo(const void* ptr) : Foo(complex_method(ptr)) {} private: Foo(const my_struct* s) : bar(calculate_bar(s)), baz(calculate_baz(s)) {} private: const bool bar; const bool baz; };

Tengo un código C ++ que se reduce a algo como lo siguiente:

class Foo{ bool bar; bool baz; Foo(const void*); }; Foo::Foo(const void* ptr){ const struct my_struct* s = complex_method(ptr); bar = calculate_bar(s); baz = calculate_baz(s); }

Semánticamente, las variables de los miembros bar y baz deben ser constantes, ya que no deben cambiar después de la inicialización. Sin embargo, parece que para hacerlos así, necesitaría inicializarlos en una lista de inicialización en lugar de asignarlos. Para ser claros, entiendo por qué necesito hacer esto. El problema es que no puedo encontrar ninguna manera de convertir el código en una lista de inicialización sin hacer una de las siguientes cosas indeseables:

  • Llame a complex_method dos veces (sería malo para el rendimiento)
  • Agregue el puntero a la clase Foo (haría el tamaño de la clase innecesariamente grande)

¿Hay alguna forma de hacer constantes las variables mientras se evitan estas situaciones indeseables?


Si no desea utilizar los constructores delegados nuevos (todavía tengo que lidiar con las versiones del compilador que no los conocen), y no desea cambiar el diseño de su clase, puede optar por una solución que reemplaza al constructor con el argumento const void * por una función miembro estática que devuelve Foo , mientras que tiene un constructor privado que toma la salida de complex_method como argumento (que es muy similar a los ejemplos del constructor delegante). La función miembro estática realiza el cálculo preliminar necesario que involucra complex_method y finaliza con el return Foo(s); . Esto requiere que la clase tenga un constructor de copia accesible, aunque su llamada (en la declaración de return ) probablemente se pueda eliminar.


Si puede pagar un compilador de C ++ 11, considere delegar constructores :

class Foo { // ... bool const bar; bool const baz; Foo(void const*); // ... Foo(my_struct const* s); // Possibly private }; Foo::Foo(void const* ptr) : Foo{complex_method(ptr)} { } // ... Foo::Foo(my_struct const* s) : bar{calculate_bar(s)} , baz{calculate_baz(s)} { }

Como consejo general, tenga cuidado al declarar a sus miembros de datos como const , ya que esto hace que su clase sea imposible de copiar-asignar y mover-asignar. Si se supone que su clase debe usarse con semántica de valor, esas operaciones se vuelven deseables. Si ese no es el caso, puede ignorar esta nota.


Una opción es un constructor delegante de C ++ 11, como se explica en otras respuestas. El método compatible con C ++ 03 es usar un subobjeto:

class Foo{ struct subobject { const bool bar; const bool baz; subobject(const struct my_struct* s) : bar(calculate_bar(s)) , baz(calculate_baz(s)) {} } subobject; Foo(const void*); }; Foo::Foo(const void* ptr) : subobject(complex_method(ptr)) {}

Puedes hacer bar y baz const, o hacer que el subobject constante, o ambos.

Si solo subobject constante de subobject , puede calcular complex_method y asignarlo a bar y baz dentro del constructor de subobject :

class Foo{ const struct subobject { bool bar; bool baz; subobject(const void*); } subobject; Foo(const void*); }; Foo::Foo(const void* ptr) : subobject(ptr) {} Foo::subobject::subobject(const void* ptr){ const struct my_struct* s = complex_method(ptr); bar = calculate_bar(s); baz = calculate_baz(s); }

La razón por la que no se pueden mutar los miembros const en el cuerpo de un constructor es que el cuerpo de un constructor se trata como cualquier otro cuerpo de función miembro, por coherencia. Tenga en cuenta que puede mover el código de un constructor a una función miembro para refactorizar, y la función miembro descontada no necesita ningún tratamiento especial.