C++ جديدة[] إلى قاعدة الطبقة مؤشر تحطم على مجموعة الوصول

StackOverflow https://stackoverflow.com/questions/829700

سؤال

عندما تخصيص كائن واحد ، هذا الكود يعمل بشكل جيد.عند محاولة إضافة مجموعة الجملة ، segfaults.لماذا هذا ؟ هدفي هنا هو أن تخفي عن العالم الخارجي حقيقة أن الفئة c يستخدم ب الكائنات داخليا.لقد نشر البرنامج codepad بالنسبة لك للعب مع.

#include <iostream>

using namespace std;

// file 1

class a
{
    public:
        virtual void m() { }
        virtual ~a() { }
};

// file 2

class b : public a
{
    int x;

    public:
        void m() { cout << "b!\n"; }
};

// file 3

class c : public a
{
    a *s;

    public:
        // PROBLEMATIC SECTION
        c() { s = new b[10]; } // s = new b;
        void m() { for(int i = 0; i < 10; i++) s[i].m(); } // s->m();
        ~c() { delete[] s; } // delete s;
        // END PROBLEMATIC SECTION
};

// file 4

int main(void)
{
    c o;

    o.m();

    return 0;
}
هل كانت مفيدة؟

المحلول

ومشكلة واحدة هي أن s[i] التعبير يستخدم مؤشر الحسابية لحساب عنوان الكائن المطلوب. منذ يعرف s كما المؤشر إلى a، والنتيجة هي الصحيحة لمجموعة من as وغير صحيحة لمجموعة من bs. دينامية ملزمة المقدمة من الميراث يعمل فقط لأساليب، أي شيء آخر (على سبيل المثال، لا أعضاء البيانات الافتراضية، لا sizeof الظاهري). وهكذا عند استدعاء الأسلوب s[i].m() يحصل على تعيين مؤشر this إلى ما يمكن أن يكون الكائن i ath في المصفوفة. ولكن منذ ذلك الحين في واقع الأمر مجموعة واحدة من bs، فإنه ينتهي (في بعض الأحيان) لافتا إلى مكان ما في منتصف كائن وتحصل على segfault (ربما عندما يحاول البرنامج الوصول vtable الكائن). كنت قد تكون قادرة على تصحيح المشكلة عن طريق virtualizing والحمولة الزائدة operator[](). (لم أكن أعتقد أنه من خلال لمعرفة ما إذا كانت ستعمل في الواقع، وإن كان.)

وثمة مشكلة أخرى هي delete في المدمر، لأسباب مشابهة. كنت قد تكون قادرة على المحاكاة الافتراضية والزائد أيضا. (مرة أخرى، مجرد فكرة العشوائية التي برزت في رأسي. قد لا يعمل).

وبطبيعة الحال، الصب (كما اقترح من قبل الآخرين) ستعمل أيضا.

نصائح أخرى

إنشاء مجموعة من 10 b'ق مع new ثم تعيين العنوان إلى a* هو يسأل عن المتاعب.

لا علاج المصفوفات polymorphically.

لمزيد من المعلومات انظر ARR39-CPP.لا علاج المصفوفات polymorphically, في القسم 06.المصفوفات و "المحكمة الخاصة بلبنان" (ARR) من سيرت C++ تأمين الترميز القياسية.

لديك مجموعة من نوع "ب" ليس من النوع "أ" و أنت تعيين مؤشر من نوع.تعدد الأشكال لا نقل إلى صفائف ديناميكية.

 a* s

إلى

 b* s

وسوف نرى هذا بدء العمل.

فقط لا بد مؤشرات يمكن علاجها polymorphically.تفكر في ذلك

 a* s = new B(); // works
 //a* is a holder for an address

 a* s = new B[10]
 //a* is a holder for an address
 //at that address are a contiguos block of 10 B objects like so
 // [B0][B2]...[B10] (memory layout)

عند تكرار عبر مجموعة باستخدام s, التفكير في ماذا يستخدم

 s[i]
 //s[i] uses the ith B object from memory. Its of type B. It has no polymorphism. 
 // Thats why you use the . notation to call m() not the -> notation

قبل تحويلها إلى مجموعة أنت فقط

 a* s = new B();
 s->m();

s هنا هو مجرد عنوان ، وليس كائن ثابت مثل s[i].مجرد عنوان في s يمكن أن يكون لا يزال حيوي ملزمة.ما هو في s ؟ من يدري ؟ شيء في عنوان s.

انظر آري's كبيرة الإجابة أدناه للحصول على مزيد من المعلومات حول لماذا هذا أيضا لا معنى له من حيث كيفية C أسلوب المصفوفات هي وضعت خارجا.

وكل مثيل B يحتوي على كل عضو بيانات X و "vptr" (المؤشر إلى الجدول الظاهري).

وكل مثيل وتحتوي فقط على "vptr"

وهكذا، sizeof (أ)! = sizeof (ب).

والآن عندما تفعل هذا الشيء: "S = ب الجديدة [10]" كنت ملقى على ذاكرة 10 حالات ب في الخام، S (الذي يحتوي على نوع من *) هو الحصول على البداية أن الخام من البيانات .

طريقة

وفي C :: م ()، لك أن تقول المترجم لتكرار عبر مجموعة من "أ" (لأن الصورة يحتوي على نوع من *)، على ولكن ، أو الصورة يشير إلى actualy مجموعة من "ب". حتى عند استدعاء الصورة [أنا] ما المترجم القيام actualy هو "ليالي + أنا * sizeof (أ)"، المترجم يقفز في وحدات من "أ" بدلا من وحدات "ب" ومنذ ذلك الحين ولم يقم ب نفس الحجم، وتحصل على الكثير من mambojumbo.

ولقد برزت والحل على أساس إجاباتك. وليسمح لي لإخفاء تفاصيل التنفيذ باستخدام طبقة من المراوغة. كما يسمح لي أن مزيج الأجسام مباراة في بلدي مجموعة. شكرا!

#include <iostream>

using namespace std;

// file 1

class a
{
    public:
        virtual void m() { }
        virtual ~a() { }
};

// file 2

class b : public a
{
    int x;

    public:
        void m() { cout << "b!\n"; }
};

// file 3

class c : public a
{
    a **s;

    public:
        // PROBLEMATIC SECTION
        c() { s = new a* [10]; for(int i = 0; i < 10; i++) s[i] = new b(); }
        void m() { for(int i = 0; i < 10; i++) s[i]->m(); }
        ~c() { for(int i = 0; i < 10; i++) delete s[i]; delete[] s; }
        // END PROBLEMATIC SECTION
};

// file 4

int main(void)
{
    c o;

    o.m();

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