Pregunta

Tengo la siguiente clase en C ++:

class a {
    const int b[2];
    // other stuff follows

    // and here's the constructor
    a(void);
}

La pregunta es, ¿cómo puedo inicializar b en la lista de inicialización, dado que no puedo inicializarla dentro del cuerpo de la función del constructor, porque b es const ?

Esto no funciona:

a::a(void) : 
    b([2,3])
{
     // other initialization stuff
}

Editar: El caso en cuestión es cuando puedo tener diferentes valores para b para diferentes instancias, pero se sabe que los valores son constantes durante toda la vida de la instancia.

¿Fue útil?

Solución

Como decían los demás, ISO C ++ no admite eso. Pero puedes solucionarlo. Solo usa std :: vector en su lugar.

int* a = new int[N];
// fill a

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};

Otros consejos

Con C ++ 11, la respuesta a esta pregunta ahora ha cambiado y, de hecho, puede hacerlo:

struct a {
    const int b[2];
    // other bits follow

    // and here's the constructor
    a();
};

a::a() :
    b{2,3}
{
     // other constructor work
}

int main() {
 a a;
}

No es posible en la norma actual. Creo que podrá hacer esto en C ++ 0x utilizando las listas de inicializadores (consulte Una breve mirada en C ++ 0x , por Bjarne Stroustrup, para obtener más información sobre las listas de inicializadores y otras características interesantes de C ++ 0x).

std :: vector usa el montón. Caray, qué desperdicio sería solo por una verificación de cordura de const . El punto de std :: vector es el crecimiento dinámico en tiempo de ejecución, no cualquier comprobación de sintaxis antigua que se deba realizar en tiempo de compilación. Si no vas a crecer, crea una clase para envolver una matriz normal.

#include <stdio.h>


template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
    size_t length;

public:
    ConstFixedSizeArrayFiller() : length(0) {
    }

    virtual ~ConstFixedSizeArrayFiller() {
    }

    virtual void Fill(Type *array) = 0;

protected:
    void add_element(Type *array, const Type & element)
    {
        if(length >= MaxLength) {
            // todo: throw more appropriate out-of-bounds exception
            throw 0;
        }
        array[length] = element;
        length++;
    }
};


template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
    Type array[Length];

public:
    explicit ConstFixedSizeArray(
        ConstFixedSizeArrayFiller<Type, Length> & filler
    ) {
        filler.Fill(array);
    }

    const Type *Array() const {
        return array;
    }

    size_t ArrayLength() const {
        return Length;
    }
};


class a {
private:
    class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
    public:
        virtual ~b_filler() {
        }

        virtual void Fill(int *array) {
            add_element(array, 87);
            add_element(array, 96);
        }
    };

    const ConstFixedSizeArray<int, 2> b;

public:
    a(void) : b(b_filler()) {
    }

    void print_items() {
        size_t i;
        for(i = 0; i < b.ArrayLength(); i++)
        {
            printf("%d\n", b.Array()[i]);
        }
    }
};


int main()
{
    a x;
    x.print_items();
    return 0;
}

ConstFixedSizeArrayFiller y ConstFixedSizeArray son reutilizables.

La primera permite la verificación de los límites del tiempo de ejecución al inicializar la matriz (igual que un vector), que luego puede convertirse en const después de esta inicialización.

El segundo permite que a la matriz se le asigne dentro de otro objeto, que podría estar en el montón o simplemente en la pila si es donde está el objeto. No hay pérdida de tiempo en la asignación de la pila. También realiza una comprobación constante en tiempo de compilación en la matriz.

b_filler es una pequeña clase privada para proporcionar los valores de inicialización. El tamaño de la matriz se verifica en tiempo de compilación con los argumentos de la plantilla, por lo que no hay posibilidad de salir de los límites.

Estoy seguro de que hay formas más exóticas de modificar esto. Esta es una puñalada inicial. Creo que puedes compensar bastante por cualquiera de las fallas del compilador con clases.

La norma ISO C ++ no te permite hacer esto. Si lo hiciera, la sintaxis probablemente sería:

a::a(void) :
b({2,3})
{
    // other initialization stuff
}

O algo por el estilo. De su pregunta, en realidad suena como que lo que quiere es un miembro de clase constante (también conocido como estático) que es la matriz. C ++ te deja hacer esto. Al igual que:

#include <iostream>

class A 
{
public:
    A();
    static const int a[2];
};

const int A::a[2] = {0, 1};

A::A()
{
}

int main (int argc, char * const argv[]) 
{
    std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
    return 0;
}

La salida es:

A::a => 0, 1

Por supuesto, ya que este es un miembro de clase estática, es el mismo para todas las instancias de la clase A. Si eso no es lo que quiere, es decir, desea que cada instancia de A tenga diferentes valores de elementos en la matriz a, entonces estamos cometiendo el error de tratar de hacer que la matriz conste para empezar. Solo deberías estar haciendo esto:

#include <iostream>

class A 
{
public:
    A();
    int a[2];
};

A::A()
{
    a[0] = 9; // or some calculation
    a[1] = 10; // or some calculation
}

int main (int argc, char * const argv[]) 
{
    A v;
    std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
    return 0;
}

Donde tengo una matriz constante, siempre se ha hecho como estática. Si puedes aceptar eso, este código debería compilarse y ejecutarse.

#include <stdio.h>
#include <stdlib.h>

class a {
        static const int b[2];
public:
        a(void) {
                for(int i = 0; i < 2; i++) {
                        printf("b[%d] = [%d]\n", i, b[i]);
                }
        }
};

const int a::b[2] = { 4, 2 };

int main(int argc, char **argv)
{
        a foo;
        return 0;
}

No puedes hacer eso desde la lista de inicialización,

Echa un vistazo a esto:

http://www.cprogramming.com/tutorial/initialization-lists -c ++. html

:)

Una solución sin usar el montón con std :: vector es usar boost :: array , aunque no puede inicializar los miembros de la matriz directamente en el constructor.

#include <boost/array.hpp>

const boost::array<int, 2> aa={ { 2, 3} };

class A {
    const boost::array<int, 2> b;
    A():b(aa){};
};

¿Qué hay de emular una matriz de const a través de una función de acceso? No es estático (como lo solicitó) y no requiere stl ni ninguna otra biblioteca:

class a {
    int privateB[2];
public:
    a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
    int b(const int idx) { return privateB[idx]; }
}

Debido a que un :: privateB es privado, es efectivamente constante fuera de un ::, y puedes acceder a él de manera similar a una matriz, por ejemplo

a aobj(2,3);    // initialize "constant array" b[]
n = aobj.b(1);  // read b[1] (write impossible from here)

Si está dispuesto a usar un par de clases, también podría proteger privateB de las funciones miembro. Esto podría hacerse heredando un; pero creo que prefiero comp.lang de John Harrison. Publicación de c ++ usando una clase const.

curiosamente, en C # tiene la palabra clave const que se traduce en constas estáticas de C ++, en lugar de solo lectura que solo se puede establecer en constructores e inicializaciones, incluso por no constantes, por ejemplo:

readonly DateTime a = DateTime.Now;

Estoy de acuerdo, si tienes una matriz predefinida de const, también podrías hacerla estática. En ese momento puede utilizar esta interesante sintaxis:

//in header file
class a{
    static const int SIZE;
    static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};

sin embargo, no encontré una manera de evitar la constante '10'. El motivo es claro, sin embargo, lo necesita para saber cómo realizar el acceso a la matriz. Una posible alternativa es usar #define, pero no me gusta ese método y yo #undef al final del encabezado, con un comentario para editar allí en CPP y en caso de que haya un cambio.

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