78

私はC++で次のクラスを持っています:

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

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

問題は、コンストラクターの関数の本体内で b を初期化できない場合、初期化リストで b を初期化する方法ですconst

これは機能しません:

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

編集: 適切なケースは、インスタンスごとに異なる値を持つことができる場合ですbが、値はインスタンスの存続期間中一定であることが知られています。

4

10 に答える 10

82

C++11 では、この質問に対する答えが変更され、実際に次のことができるようになりました。

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;
}
于 2011-10-18T11:11:53.877 に答える
35

他の人が言ったように、ISO C++ はそれをサポートしていません。しかし、あなたはそれを回避することができます。代わりに std::vector を使用してください。

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

class C {
  const std::vector<int> v;
public:
  C():v(a, a+N) {}
};
于 2008-10-02T13:52:14.437 に答える
25

現在の規格では不可能です。初期化子リストを使用して C++0x でこれを実行できると思います (初期化子リストとその他の優れた C++0x 機能の詳細については、Bjarne Stroustrup によるA Brief Look at C++0x を参照してください)。

于 2008-10-02T11:31:48.083 に答える
13

std::vectorヒープを使用します。constまったく、正気度チェックのためだけになんてもったいない。ポイントはstd::vector、実行時の動的な拡張であり、コンパイル時に実行する必要がある古い構文チェックではありません。成長しない場合は、通常の配列をラップするクラスを作成します。

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

ConstFixedSizeArrayFillerConstFixedSizeArray利用可能です。

1 つ目は、配列の初期化中に実行時の境界チェックを許可します (ベクトルと同じ)。これは、後でconstこの初期化の後に行うことができます。

2 つ目は、別のオブジェクト内に配列を割り当てることができます。これは、オブジェクトが存在する場合は、ヒープまたは単にスタック上にある可能性があります。ヒープから割り当てる時間の無駄はありません。また、配列に対してコンパイル時の const チェックも実行します。

b_filler初期化値を提供する小さなプライベート クラスです。配列のサイズはコンパイル時にテンプレート引数でチェックされるため、範囲外になる可能性はありません。

これを変更するためのよりエキゾチックな方法があると確信しています。これが初刺です。クラスに関するコンパイラの欠点をほぼ補うことができると思います。

于 2010-04-15T04:21:07.973 に答える
10

ISO 標準 C++ では、これを行うことはできません。その場合、構文はおそらく次のようになります。

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

または、それらの線に沿った何か。あなたの質問から、実際には、配列である定数クラス(別名静的)メンバーが必要なように聞こえます。C++ ではこれを行うことができます。そのようです:

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

出力は次のとおりです。

A::a => 0, 1

もちろん、これは静的クラス メンバーであるため、クラス A のすべてのインスタンスで同じです。それが必要でない場合、つまり、A の各インスタンスに配列 a の異なる要素値を持たせたい場合は、次のようにします。そもそも配列を const にしようとするミス。これを行う必要があります:

#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;
}
于 2008-10-02T11:50:26.320 に答える
4

初期化リストからそれを行うことはできません。

これを見てください:

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

:)

于 2008-10-02T11:28:35.390 に答える
4

私が定数配列を持っている場合、それは常に静的として行われています。それを受け入れることができれば、このコードをコンパイルして実行する必要があります。

#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;
}
于 2008-10-02T11:34:56.857 に答える
3

アクセサー関数を介して const 配列をエミュレートするのはどうですか? それは(あなたが要求したように)非静的であり、stlやその他のライブラリを必要としません:

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

a::privateB は非公開であるため、a:: の外では事実上定数であり、配列と同様にアクセスできます。

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

クラスのペアを使用する場合は、privateB をメンバー関数からさらに保護できます。これは、a; を継承することで実行できます。しかし、const クラスを使用した John Harrison の comp.lang.c++ の投稿の方が好きだと思います。

于 2011-06-10T14:52:04.573 に答える
3

ヒープを使用しない解決策std::vectorは、を使用するboost::arrayことですが、コンストラクターで配列メンバーを直接初期化することはできません。

#include <boost/array.hpp>

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

class A {
    const boost::array<int, 2> b;
    A():b(aa){};
};
于 2010-05-18T22:24:27.427 に答える
2

興味深いことに、C# には、C++ の static const に変換されるキーワード const があります。これは、非定数であっても、コンストラクターと初期化でのみ設定できる readonly とは対照的です。例:

readonly DateTime a = DateTime.Now;

const 定義済みの配列がある場合は、それを静的にすることもできます。その時点で、次の興味深い構文を使用できます。

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

ただし、定数「10」を回避する方法が見つかりませんでした。理由は明らかですが、配列へのアクセスを実行する方法を知る必要があります。考えられる代替手段は #define を使用することですが、私はその方法が嫌いで、ヘッダーの最後に #undef を付けて、変更があった場合に備えて CPP で編集するコメントを付けます。

于 2009-05-28T17:44:12.840 に答える