簡體   English   中英

在C ++中的類初始值設定項中初始化const數組

[英]initialize a const array in a class initializer in C++

我在C ++中有以下課程:

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

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

問題是,由於b是const ,我無法在構造函數的函數體內對其進行初始化,因此如何在初始化列表中初始化b?

這不起作用:

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

編輯:恰當的例子是當我可以為不同的實例設置b的不同值,但已知該值在實例的生存期內是恆定的。

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

就像其他人說的那樣,ISO C ++不支持該功能。 但是您可以解決它。 只需使用std :: vector即可。

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

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

在當前標准中是不可能的。 我相信你就可以做到這一點在C ++中使用初始化列表(見0X 簡單的介紹一下的C ++ 0x ,由Bjarne Stroustrup的,有關初始化列表和其他不錯的C ++ 0x功能的更多信息)。

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可重用。

第一個允許在初始化數組時進行運行時邊界檢查(與向量可能相同),此數組在初始化之后可以變為const

第二個允許將數組分配另一個對象內,該對象可以在堆上,或者如果是對象所在的地方,則可以只是堆棧。 從堆分配資源沒有浪費時間。 它還在數組上執行編譯時常量檢查。

b_filler是一個很小的私有類,用於提供初始化值。 數組的大小是在編譯時使用模板參數進行檢查的,因此不會超出范圍。

我敢肯定,還有更多異國情調的方法可以對此進行修改。 這是最初的刺傷。 我認為您幾乎可以彌補編譯器類的缺點。

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

您無法從初始化列表中執行此操作,

看看這個:

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

:)

在我有一個常量數組的地方,它總是作為靜態完成的。 如果您可以接受,則此代碼應編譯並運行。

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

不將堆與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){};
};

如何通過訪問器函數模擬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;來完成。 但是我想我更喜歡John Harrison的使用const類的comp.lang.c ++帖子。

有趣的是,在C#中,關鍵字const可轉換為C ++的靜態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處進行了注釋,以防萬一發生更改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM