Domanda

Ho la seguente classe in C ++:

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

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

La domanda è: come posso inizializzare b nell'elenco di inizializzazione, dato che non posso inizializzarlo all'interno del corpo della funzione del costruttore, perché b è const ?

Questo non funziona:

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

Modifica: il caso in questione è quando posso avere valori diversi per b per istanze diverse, ma i valori sono noti per essere costanti per la durata dell'istanza.

È stato utile?

Soluzione

Come hanno detto gli altri, ISO C ++ non lo supporta. Ma puoi risolverlo. Usa invece std :: vector.

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

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

Altri suggerimenti

Con C ++ 11 la risposta a questa domanda ora è cambiata e in effetti puoi farlo:

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

Non è possibile nello standard attuale. Credo che sarai in grado di farlo in C ++ 0x usando gli elenchi di inizializzatori (vedi Un breve sguardo su C ++ 0x , di Bjarne Stroustrup, per ulteriori informazioni sugli elenchi di inizializzatori e altre belle funzionalità di C ++ 0x).

std :: vector utilizza l'heap. Accidenti, che spreco sarebbe solo per il bene di un controllo di sanità mentale const . Il punto di std :: vector è la crescita dinamica in fase di esecuzione, non un vecchio controllo della sintassi che dovrebbe essere eseguito in fase di compilazione. Se non hai intenzione di crescere, crea una classe per avvolgere un array normale.

#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 e ConstFixedSizeArray sono riutilizzabili.

Il primo consente il controllo dei limiti di runtime durante l'inizializzazione dell'array (come un vettore potrebbe), che può successivamente diventare const dopo questa inizializzazione.

Il secondo consente all'array di essere allocato dentro un altro oggetto, che potrebbe essere nell'heap o semplicemente nello stack se è lì che si trova l'oggetto. Non ci sono perdite di tempo da dedicare dall'heap. Esegue anche il controllo const in fase di compilazione sull'array.

b_filler è una piccola classe privata per fornire i valori di inizializzazione. La dimensione dell'array viene verificata in fase di compilazione con gli argomenti del modello, quindi non c'è possibilità di andare oltre i limiti.

Sono sicuro che ci sono modi più esotici per modificarlo. Questa è una pugnalata iniziale. Penso che tu possa praticamente compensare qualsiasi carenza del compilatore con le classi.

Lo standard ISO C ++ non ti consente di farlo. In tal caso, la sintassi sarebbe probabilmente:

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

O qualcosa del genere. Dalla tua domanda sembra che quello che vuoi sia un membro di classe costante (aka statico) che è l'array. C ++ ti consente di farlo. In questo modo:

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

L'output è:

A::a => 0, 1

Ora, naturalmente, poiché si tratta di un membro di classe statico, è lo stesso per ogni istanza della classe A. Se non è quello che si desidera, ovvero si desidera che ogni istanza di A abbia valori di elementi diversi nell'array a allora si stai facendo l'errore di provare a rendere l'array const per cominciare. Dovresti semplicemente fare questo:

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

Dove ho un array costante, è sempre stato fatto come statico. Se puoi accettarlo, questo codice dovrebbe essere compilato ed eseguito.

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

Non puoi farlo dall'elenco di inizializzazione,

Dai un'occhiata a questo:

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

:)

Una soluzione senza usare l'heap con std :: vector è usare boost :: array , sebbene non sia possibile inizializzare i membri dell'array direttamente nel costruttore.

/ p>

#include <boost/array.hpp>

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

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

Che ne dici di emulare un array const tramite una funzione accessor? È non statico (come richiesto) e non richiede stl o altre librerie:

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

Poiché a :: privateB è privato, è effettivamente costante al di fuori di :: e puoi accedervi in ??modo simile a un array, ad es.

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

Se si desidera utilizzare una coppia di classi, è possibile proteggere ulteriormente privateB dalle funzioni membro. Questo potrebbe essere fatto ereditando a; ma penso di preferire Comp.lang di John Harrison. post c ++ usando una classe const.

interessante, in C # hai la parola chiave const che si traduce nella const statica di C ++, al contrario di readonly che può essere impostata solo su costruttori e inizializzazioni, anche da non costanti, es:

readonly DateTime a = DateTime.Now;

Sono d'accordo, se hai un array predefinito const potresti anche renderlo statico. A quel punto puoi usare questa interessante sintassi:

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

tuttavia, non ho trovato un modo per aggirare la costante '10'. Il motivo è chiaro, tuttavia, è necessario che sappia come eseguire l'accesso all'array. Una possibile alternativa è usare #define, ma non mi piace quel metodo e #undef alla fine dell'intestazione, con un commento da modificare lì su CPP e nel caso in cui una modifica.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top