سؤال

لدي الفصل التالي في 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 بالنسبة لحالات مختلفة ، ولكن من المعروف أن القيم ثابتة لعمر المثيل.

هل كانت مفيدة؟

المحلول

كما قال الآخرون ، لا يدعم ISO C ++ ذلك. لكن يمكنك حلها. فقط استخدم std :: ناقلات بدلاً من ذلك.

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

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

نصائح أخرى

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

هذا غير ممكن في المعيار الحالي. أعتقد أنك ستتمكن من القيام بذلك في 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;
}

ConstFixedSizeArrayFiller و ConstFixedSizeArray يمكن إعادة استخدامها.

الأول يسمح بالتحقق من حدود وقت التشغيل أثناء تهيئة الصفيف (نفس المتجه) ، والذي يمكن أن يصبح لاحقًا const بعد هذا التهيئة.

والثاني يسمح لتخصيص الصفيف داخل كائن آخر ، والذي يمكن أن يكون على الكومة أو ببساطة المكدس إذا كان هذا هو المكان الذي يوجد فيه الكائن. لا يوجد مضيعة للوقت في تخصيص الكومة. كما أنه يؤدي فحص Const وقت الترجمة على الصفيف.

b_filler هي فئة خاصة صغيرة لتوفير قيم التهيئة. يتم فحص حجم الصفيف في وقت الترجمة مع حجج القالب ، لذلك لا توجد فرصة للخروج من الحدود.

أنا متأكد من أن هناك طرقًا أكثر غرابة لتعديل هذا. هذه طعنة أولية. أعتقد أنه يمكنك تعويض أي من أوجه القصور المترجم مع الفصول الدراسية.

لا يسمح لك ISO Standard C ++ بذلك. إذا حدث ذلك ، فمن المحتمل أن يكون بناء الجملة:

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

او هناك شيء ما على طول هذه الخطوط. من سؤالك يبدو في الواقع ما تريده هو عضو ثابت (ويعرف أيضًا باسم Static) وهو الصفيف. 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 ، فأنت تصنع خطأ في محاولة جعل الصفيف 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;
}

حيث يكون لدي صفيف ثابت ، تم القيام به دائمًا على أنه ثابت. إذا كنت تستطيع قبول ذلك ، فيجب تجميع هذا الرمز وتشغيله.

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

لا يمكنك فعل ذلك من قائمة التهيئة ،

الق نظرة على هذا:

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

:)

حل دون استخدام الكومة مع 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]; }
}

لأن :: privateB خاص ، فهو ثابت فعليًا خارج A :: ، ويمكنك الوصول إليه مشابهًا لمجموعة ، على سبيل المثال

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

إذا كنت على استعداد لاستخدام زوج من الفصول ، فيمكنك حماية PrivateB من وظائف الأعضاء. يمكن القيام بذلك عن طريق وراثة أ ؛ لكني أعتقد أنني أفضل John Harrison's Comp.lang.c ++ post باستخدام فئة const.

ومن المثير للاهتمام ، في C# لديك الكلمة الرئيسية التي تترجم إلى C ++ الثابتة ، بدلاً من القراءة التي يمكن تعيينها فقط على المُنشئين والتهيئة ، حتى من قبل غير المستقلين ، على سبيل المثال:

readonly DateTime a = DateTime.Now;

أوافق ، إذا كان لديك صفيف محدد مسبقًا ، فقد تجعله ثابتًا. في هذه المرحلة ، يمكنك استخدام هذا الجملة المثيرة للاهتمام:

//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 ، لكنني لا أحب هذه الطريقة و I #undef في نهاية الرأس ، مع تعليق لتحرير هناك في CPP وكذلك في حالة تغيير.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top