كيف برنامج التحويل البرمجي C++ تعرف أي تنفيذ دالة ظاهري الاتصال ؟

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

  •  03-07-2019
  •  | 
  •  

سؤال

هنا هو مثال على تعدد الأشكال من http://www.cplusplus.com/doc/tutorial/polymorphism.html (تنقيح القراءة):

// abstract base class
#include <iostream>
using namespace std;

class Polygon {
    protected:
        int width;
        int height;
    public:
        void set_values(int a, int b) { width = a; height = b; }
        virtual int area(void) =0;
};

class Rectangle: public Polygon {
    public:
        int area(void) { return width * height; }
};

class Triangle: public Polygon {
    public:
        int area(void) { return width * height / 2; }
};

int main () {
    Rectangle rect;
    Triangle trgl;
    Polygon * ppoly1 = &rect;
    Polygon * ppoly2 = &trgl;
    ppoly1->set_values (4,5);
    ppoly2->set_values (4,5);
    cout << ppoly1->area() << endl; // outputs 20
    cout << ppoly2->area() << endl; // outputs 10
    return 0;
}

سؤالي هو كيف مترجم نعلم أن ppoly1 هو مستطيل و أن ppoly2 هو مثلث بحيث يمكن استدعاء منطقة الصحيح() وظيفة ؟ ويمكن معرفة ذلك من خلال النظر في "المضلع * ppoly1 = ▭" سطر مع العلم أن المستطيل هو مستطيل ، لكن ذلك لن ينجح في كل الحالات ؟ ما إذا كنت فعلت شيئا مثل هذا ؟

cout << ((Polygon *)0x12345678)->area() << endl;

على افتراض أن كنت يسمح لك للوصول إلى منطقة عشوائية من الذاكرة.

وأود أن اختبار هذا الخروج ولكن لا أستطيع على الكمبيوتر أنا في هذه اللحظة.

(آمل أنا لست في عداد المفقودين شيء واضح...)

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

المحلول

وكل كائن (الذي ينتمي إلى فئة مع وظيفة افتراضية واحدة على الأقل) لديه مؤشر، ودعا vptr. يشير إلى vtbl من فئتها الفعلية (التي كل فئة مع الدالات الظاهرية واحد على الأقل من، ربما أكثر من واحد لبعض سيناريوهات متعددة الميراث).

ووvtbl يحتوي على مجموعة من المؤشرات، واحدة لكل وظيفة افتراضية. حتى في وقت التشغيل، رمز يستخدم فقط vptr الكائن لتحديد موقع vtbl، وهناك من عنوان الدالة تجاوز الفعلية.

في قضيتك محددة، Polygon، Rectangle، وTriangle لكل منها vtbl، مع كل واحد لافتا دخول إلى طريقتها area ذات الصلة. سوف ppoly1 الخاصة بك يكون لها vptr مشيرا إلى Rectangle vtbl، ووppoly2 بالمثل مع Triangle vtbl ل. ويساعد هذا الأمل!

نصائح أخرى

<وأ href = "https://stackoverflow.com/questions/203126/how-does-the-c-compiler-know-which-implementation-of-a-virtual-function-to-call#203136" > كريس المهرج يونغ يعطي الجواب الأساسية على هذا السؤال.

ويكيبيديا لديها أكثر في العلاج العمق.

إذا كنت تريد أن تعرف التفاصيل الكاملة لكيفية عمل هذا النوع من الشيء (ولكل نوع من الميراث، بما في ذلك متعددة والميراث الظاهري)، واحدة من أفضل الموارد هو "<لأ href =" ستان ليبمان في الشبكي: / /rads.stackoverflow.com/amzn/click/com/0201834545 "يختلط =" نوفولو noreferrer "> داخل C ++ طراز كائن ".

وتجاهل جوانب ملزمة، انها ليست في الواقع المترجم الذي يحدد ذلك.

ومن وقت التشغيل C ++ أن يقيم، عبر vtables وvpointers، ما هو كائن اشتقاق فعلا في وقت التشغيل.

وأنا أوصي كتاب الفعالة C سكوت ماير ++ لوصف جيد على كيفية القيام بذلك.

وحتى يغطي كيف يتم تجاهل المعلمات الافتراضية في أسلوب في فئة مشتقة وأي المعلمات الافتراضية في الفئة الأساسية لا تزال أخذ! وهذا ما ملزمة.

للرد على الجزء الثاني من سؤالك: هذا العنوان ربما لن يكون لها جدول الخامس في المكان المناسب، وسوف الجنون تترتب على ذلك. أيضا، هو غير معروف وفقا لهذا المعيار.

cout << ((Polygon *)0x12345678)->area() << endl;

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

في C++, لا يجب استخدام القديمة ج-أسلوب يلقي مثل هذا, يجب عليك استخدام dynamic_cast مثل ذلك:

Polygon *obj = dynamic_cast<Polygon *>(0x12345678)->area();
ASSERT(obj != NULL);

cout << obj->area() << endl;

dynamic_cast سيعود لاغية إذا كان إعطاء مؤشر غير صالح الكائن المضلع لذلك سوف يكون محاصرا من قبل التأكيد.

والجداول وظيفة افتراضية. لفيت، سواء من الأشياء المستمدة مضلع الخاص لديك جدول ظيفة الظاهري الذي يحتوي على مؤشرات الدالة إلى تطبيقات كل ما لديهم وظائف (غير ثابت)؛ وعند مثيل المثلث، مؤشر الدالة الظاهري للمنطقة () نقطة وظيفة إلى المثلث :: مساحة () وظيفة. عند مثيل مستطيل، ومنطقة () نقطة وظيفة للمستطيل منطقة) وظيفة :: (. لأنه يتم تخزين مؤشرات دالة الظاهري جنبا إلى جنب مع البيانات لكائن في الذاكرة، في كل مرة كنت مرجع هذا الكائن كما مضلع، المنطقة المناسبة () لوسيتم استخدام هذا الكائن.

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