inicjalizacja tablicy const w inicjalizatorze klasy w C++

Mam następującą klasę w C++:

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

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

Pytanie brzmi, jak zainicjować b na liście inicjalizacji, biorąc pod uwagę, że nie mogę zainicjować go wewnątrz ciała funkcji konstruktora, ponieważ b jest const?

To nie działa:

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

Edit: w tym przypadku mogę mieć różne wartości dla b dla różnych instancji, ale wartości są znane jako stałe przez cały okres istnienia instancji.

Author: Lightness Races in Orbit, 2008-10-02

10 answers

Jak inni mówili, ISO C++ tego nie obsługuje. Ale możesz to obejść. Zamiast tego użyj std:: vector.

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

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};
 30
Author: Weipeng L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 13:52:14

W C++11 odpowiedź na to pytanie się zmieniła i w rzeczywistości można to zrobić:

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;
}
 70
Author: Flexo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-30 14:31:17

Nie jest to możliwe w obecnym standardzie. Wierzę, że będziesz w stanie to zrobić w C++0x używając list inicjujących (zobacz a Brief Look at C++0x, By Bjarne Stroustrup, aby uzyskać więcej informacji na temat list inicjujących i innych ładnych funkcji C++0x).

 25
Author: Luc Touraille,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 11:31:48

std::vector używa sterty. Jejku, co za strata by to było dla dobra zdrowego rozsądku. Punktem std::vector jest dynamiczny wzrost w czasie wykonywania, a nie Stare sprawdzanie składni, które powinno być wykonywane w czasie kompilacji. Jeśli nie masz zamiaru rosnąć, Utwórz klasę, aby owinąć normalną tablicę.

#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 i ConstFixedSizeArray są wielokrotnego użytku.

Pierwszy pozwala na sprawdzanie granic podczas inicjalizacji tablicy (tak samo jak wektor), która później może stać się const po tym inicjalizacja.

Drugi pozwala na przydzielenie tablicy wewnątrz innego obiektu, który może znajdować się na stercie lub po prostu na stosie, jeśli tam znajduje się obiekt. Nie ma marnowania czasu na rozdzielanie się ze sterty. Wykonuje również sprawdzanie konst w czasie kompilacji na tablicy.

b_filler jest małą klasą prywatną, która dostarcza wartości inicjalizacji. Rozmiar tablicy jest sprawdzany w czasie kompilacji z argumentami szablonu, więc nie ma szans na wyjście z / align = "left" /

Jestem pewien, że są bardziej egzotyczne sposoby, aby to zmodyfikować. To pierwsze pchnięcie. Myślę, że możesz nadrobić wszelkie niedociągnięcia kompilatora w klasach.

 12
Author: Matthew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-15 04:21:07

ISO standard C++ nie pozwala ci na to. Gdyby tak było, składnia prawdopodobnie brzmiałaby:

a::a(void) :
b({2,3})
{
    // other initialization stuff
}
Albo coś w tym stylu. Z twojego pytania wynika, że to, co chcesz, to stały członek klasy (aka static), który jest tablicą. C++ pozwala ci na to. Tak:
#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;
}

Wyjście jest:

A::a => 0, 1

Teraz oczywiście, ponieważ jest to statyczny członek klasy, jest tak samo dla każdej instancji klasy A. Jeśli tego nie chcesz, tj. instancja a, aby mieć różne wartości elementów w tablicy a, popełniasz błąd próbując utworzyć tablicę const na początek. Powinieneś to robić:

#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;
}
 8
Author: orj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 11:50:26

Gdzie mam stałą tablicę, zawsze robiono to jako statyczne. Jeśli możesz to zaakceptować, ten kod powinien się skompilować i uruchomić.

#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;
}
 4
Author: Daniel Bungert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-02 11:43:11

Nie możesz tego zrobić z listy inicjalizacji,

Spójrz na to:

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

:)

 4
Author: Trap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-18 21:14:28

Rozwiązaniem bez użycia sterty z std::vector jest użycie boost::array, chociaż nie można zainicjować członków tablicy bezpośrednio w konstruktorze.

#include <boost/array.hpp>

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

class A {
    const boost::array<int, 2> b;
    A():b(aa){};
};
 3
Author: CharlesB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-18 22:24:27

A może emulacja tablicy const przez funkcję accessora? Jest niestatyczna (zgodnie z Twoim życzeniem) i nie wymaga stl ani żadnej innej biblioteki:

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

Ponieważ a:: privateB jest prywatne, jest ona w rzeczywistości stała poza a::, i można uzyskać do niej dostęp podobny do tablicy, np.

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

Jeśli chcesz użyć pary klas, możesz dodatkowo chronić privateB przed funkcjami członkowskimi. Można to zrobić poprzez dziedziczenie a; ale myślę, że wolę Johna Harrisona komp.lang.C++ post przy użyciu klasy const.

 3
Author: Pete,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-17 13:16:01

Co ciekawe, w C# masz słowo kluczowe const, które tłumaczy się na statyczne const w C++, w przeciwieństwie do readonly, które może być ustawione tylko w konstruktorach i inicjalizacjach, nawet przez nie-stałe, np:

readonly DateTime a = DateTime.Now;

Zgadzam się, jeśli masz wstępnie zdefiniowaną tablicę const, równie dobrze możesz uczynić ją statyczną. W tym momencie możesz użyć tej interesującej składni:

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

Jednak nie znalazłem sposobu na obejście stałej "10". Powód jest jednak jasny, potrzebuje go, aby wiedzieć, jak wykonać dostęp do tablicy. Ewentualną alternatywą jest użycie #define, ale nie lubię tej metody i #undef na końcu nagłówka, z komentarzem do edycji tam w CPP, jak również w przypadku zmiany.

 2
Author: Nefzen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-29 00:01:00