Question

J'ai la classe suivante en C ++:

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

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

La question est de savoir comment initialiser b dans la liste d'initialisation, étant donné que je ne peux pas l'initialiser dans le corps de la fonction du constructeur, car b est const ?

Cela ne fonctionne pas:

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

Modifier: le cas d'espèce est celui où je peux avoir différentes valeurs pour b pour différentes instances, mais les valeurs sont connues pour être constantes pendant toute la durée de vie de l'instance.

Était-ce utile?

La solution

Comme d'autres l'ont dit, ISO C ++ ne prend pas cela en charge. Mais vous pouvez contourner le problème. Utilisez simplement std :: vector à la place.

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

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

Autres conseils

Avec C ++ 11, la réponse à cette question a maintenant changé et vous pouvez en fait:

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;
}

Cela n’est pas possible dans la norme actuelle. Je pense que vous pourrez le faire en C ++ 0x en utilisant des listes d’initialisation (voir bref aperçu sur C ++ 0x , par Bjarne Stroustrup, pour plus d’informations sur les listes d’initialisation et d’autres fonctionnalités intéressantes de C ++ 0x).

std :: vector utilise le tas. Décidément, quel gâchis ce ne serait que pour un contrôle de cohérence const . Le point de std :: vector est une croissance dynamique au moment de l'exécution, pas une vérification de la syntaxe ancienne qui devrait être effectuée au moment de la compilation. Si vous ne voulez pas grandir, créez une classe pour envelopper un tableau 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 et ConstFixedSizeArray sont réutilisables.

Le premier autorise la vérification des limites au moment de l’exécution lors de l’initialisation du tableau (de la même manière qu’un vecteur peut être), ce qui peut devenir ultérieurement const après cette initialisation.

Le second permet d'allouer au tableau à l'intérieur d'un autre objet, qui pourrait se trouver sur le tas ou simplement sur la pile, si tel est le cas. Il n'y a pas de perte de temps à allouer du tas. Il effectue également une vérification constante au moment de la compilation sur le tableau.

b_filler est une toute petite classe privée fournissant les valeurs d'initialisation. La taille du tableau est vérifiée au moment de la compilation avec les arguments du modèle, il n’ya donc aucune chance de sortir des limites.

Je suis sûr qu'il existe des moyens plus exotiques de modifier cela. Ceci est un coup de couteau initial. Je pense que vous pouvez compenser les inconvénients du compilateur avec les classes.

La norme ISO C ++ ne vous permet pas de le faire. Si c'était le cas, la syntaxe serait probablement la suivante:

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

Ou quelque chose du genre. D'après votre question, cela ressemble en fait à ce que vous voulez, c'est un membre de classe constant (ou statique) qui est le tableau. C ++ vous laisse faire cela. Comme si:

#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 sortie étant:

A::a => 0, 1

Bien sûr, puisqu'il s'agit d'un membre statique de la classe, il en est de même pour chaque instance de la classe A. Si ce n'est pas ce que vous voulez, c'est-à-dire que vous voulez que chaque instance de A ait des valeurs d'élément différentes dans le tableau a commettez l'erreur d'essayer de faire le tableau const pour commencer. Vous devriez juste faire ceci:

#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;
}

Là où j'ai un tableau constant, cela a toujours été fait en statique. Si vous pouvez accepter cela, ce code devrait être compilé et exécuté.

#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;
}

Vous ne pouvez pas faire cela à partir de la liste d'initialisation,

Regardez ceci:

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

:

Une solution sans utiliser le tas avec std :: vector consiste à utiliser boost :: array , bien que vous ne puissiez pas initialiser les membres du tableau directement dans le constructeur.

#include <boost/array.hpp>

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

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

Que diriez-vous d'émuler un tableau const via une fonction d'accesseur? C'est non statique (comme vous l'avez demandé), et cela ne nécessite ni stl ni aucune autre bibliothèque:

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

Etant donné que a :: privateB est privé, il est en réalité constant en dehors de a ::, et vous pouvez y accéder comme un tableau, par exemple.

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

Si vous souhaitez utiliser une paire de classes, vous pouvez également protéger privateB des fonctions membres. Cela pourrait être fait en héritant d'un; mais je pense que je préfère les Le document comp.lang de John Harrison. publication c ++ utilisant une classe const.

curieusement, en C #, vous avez le mot-clé const qui se traduit par la constante statique de C ++, par opposition à readonly, qui ne peut être défini que par les constructeurs et les initialisations, même par des non-constantes, ex:

readonly DateTime a = DateTime.Now;

Je suis d'accord, si vous avez un tableau prédéfini const, vous pouvez aussi le rendre statique. À ce stade, vous pouvez utiliser cette syntaxe intéressante:

//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", "!"};

Cependant, je n'ai pas trouvé le moyen de contourner la constante '10'. La raison est claire, cependant, il lui faut savoir comment effectuer un accès au tableau. Une alternative possible est d'utiliser #define, mais je n'aime pas cette méthode et je #undef à la fin de l'en-tête, avec un commentaire à éditer ici au CPP aussi au cas où il y aurait un changement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top