Pregunta

Considere una clase como esta:

class MyReferenceClass
{
public:
    MyReferenceClass();
    const double ImportantConstant1;
    const double ImportantConstant2;
    const double ImportantConstant3;
private:
    void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3);
}

Hay una rutina (ComputeImportantConstants) que calcula las tres constantes en tiempo de ejecución.Supongamos que el cálculo es bastante complejo, y de por sí produce los tres valores a la vez.Por otra parte, los resultados dependen de la configuración de compilación, por lo que codificar los resultados no es una opción.

Es allí una manera sensata para almacenar estos valores calculados en la correspondiente const doble campos de la clase?

Si no, se puede sugerir una forma más natural para declarar una clase en C++?

En C# que me gustaría utilizar una clase estática con un constructor estático aquí, pero que no es una opción en C++.También he pensado en hacer ImportantConstant1..3 no-const campos o las llamadas a la función, pero ambos parecen inferiores.

La única manera de inicializar const campos que he encontrado es el uso de inicializador de las listas de, pero no parece posible pasar los resultados de un multi-salida de la computación en dicha lista.

¿Fue útil?

Solución

¿Por qué no puedes hacer:

MyReferenceClass ComputeImportantConstants(){
    //stuff to compute
    return MyReferenceClass( const1, const2, const3 );
}

MyReferenceClass{
public:
    MyReferenceClass(double _1, double _2, double _3) 
        : m_Const1(_1),
        m_Const2(_2),
        m_Const3(_3){}

    double getImportantConst1() const { return m_Const1; }
    double getImportantConst2() const { return m_Const2; }
    double getImportantConst3() const { return m_Const3; }
private:
    const double m_Const1,
                 m_Const2,
                 m_Const3;
};

¿Así que y tienen la función de calcular se convierte en una función de fábrica?

Otros consejos

Primero: puedes hacer el mal: echar unas const const en ComputeImPorantantsstants () y colocar los valores allí.Sin embargo, no lo hagas, porque entonces te mientes al compilador y intentará encontrar la forma más desagradable de pagar.

segundo:

hacer algo como esto:

class A
private:
  double important1;
  double important2;
  double important3;
  A() { ComputeImportantConstants(); } //no need for parameters, it accesses the members
  void ComputeImportantConstants();
public:
  inline double GetImportant1() { return important1; }
  inline double GetImportant2() { return important2; }
  inline double GetImportant3() { return important3; }
};

Todavía puede mejorar esta clase al hacerlo algún tipo de singleto o así (ya que desea que se haga el cálculo solo una vez).

Usted puede mover el const los campos de una clase base, y luego pasar un contenedor de clase para inicializar ellos:

class MyBase
{
protected:
    const double ImportantConstant1;
    const double ImportantConstant2;
    const double ImportantConstant3;

    struct Initializer
    {
        double d1;
        double d2;
        double d3;
    };

    MyBase(Initializer const& i):
        ImportantConstant1(i.d1),ImportantConstant2(i.d2),ImportantConstant3(i.d3)
    {}
};

class MyReferenceClass:
    private MyBase
{
public:
    using MyBase::ImportantConstant1;
    using MyBase::ImportantConstant2;
    using MyBase::ImportantConstant3;
    MyReferenceClass():
        MyBase(makeInitializer())
    {}

private:
    MyBase::Initializer makeInitializer()
    {
        MyBase::Initializer i;
        ComputeImportantConstants(&i.d1,&i.d2,&i.d3);
        return i;
    }

    void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3);
};

La única forma de inicializar los campos Const que encontré es usar las listas de inicializador, pero no parece posible pasar los resultados de un cálculo de varias salidas en tal lista.

Eso es cierto; Sin embargo, podría inicializar a un solo miembro, que es una estructura de constantes. Ver más abajo.

También he considerado hacer lo importante, ya sea campos no const o llamadas de función, pero ambos parecen inferiores.

No creo que las funciones de Getter sean inferiores. El compilador probablemente lo enlizaría. Considere esto:

class MyReferenceClass
{
public:
    MyReferenceClass() : m_constants( ComputeImportantConstants() ) { }

    inline double ImportantConstant1() const { return m_constants.c1; }
    inline double ImportantConstant2() const { return m_constants.c2; }
    inline double ImportantConstant3() const { return m_constants.c3; }

private:
    struct Constants {
        Constants( double c1_, double c2_, double c3_ ) : c1( c1_ ), c2( c2_ ), c3( c3_ ) { }

        const double c1;
        const double c2;
        const double c3;
    };

    Constants ComputeImportantConstants() {
        return Constants( 1.0, 2.0, 3.0 );
    }

    const Constants m_constants;
};

Dado que m_constants, así como todos sus campos son constantes, los valores no pueden ser cambiados por otros métodos de Miembros, justo en el código que bosquejó en su pregunta. Una inicialización puede ser Utilizado aquí desde que inicializamos un solo valor: una estructura.

El acceso a las constantes es (lo más probable) para ser tan eficiente como antes: la sugerencia de enlinear las funciones y el compilador es muy probable que lo haga, así que se dan cuán pequeños son los getters.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top