سؤال

وقرأت أن في وقت مبكر C ++ "المجمعين" تترجم في الواقع رمز C ++ إلى C ويستخدم مترجم C على الواجهة الخلفية، وهذا جعلني أتساءل. لقد حصلت على المعرفة التقنية ما يكفي للالتفاف رأسي حول معظم كيف يمكن أن تعمل، ولكن أنا لا يمكن معرفة كيفية القيام الميراث الطبقة دون دعم اللغة لذلك.

وعلى وجه التحديد، كيف يمكن تعريف فئة مع عدد قليل من الحقول، ثم مجموعة من الفئات الفرعية التي ترث منه وكل إضافة حقول جديدة خاصة بهم، وتكون قادرة على تمرير حول لهم بالتبادل كوسائط وظيفة؟ وخصوصا كيف يمكنك أن تفعل ذلك عندما C ++ يسمح لك لتخصيص الكائنات على كومة، لذلك قد لا يكون لديك حتى مؤشرات إلى الاختباء وراء؟

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

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

المحلول

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

ويجب أن يتم تهيئتها باستخدام دالة الذي ينفذ العمل المنشئ لديك "الطبقات". هذا وسوف تشمل تهيئة مؤشر إلى جدول مؤشرات الدالة متعددة الأشكال عن وظائف افتراضية. ولإجراء مكالمات وظيفة الافتراضية من خلال مؤشر الدالة vtbl (والتي سوف تشير إلى وجود هيكل مؤشرات الدالة - واحد لكل وظيفة الظاهرية).

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

وبعض آليات هذا قد تكون مخفية / بمساعدة باستخدام وحدات الماكرو.

وطبعة ميرو Samek الأولى من "Statecharts العملية في C / C ++" لديه الملحق أ - "C + - البرمجة الشيئية في C" الذي لديه مثل هذه وحدات الماكرو. يبدو مثل هذا أسقطت من الطبعة الثانية. ربما لأنه أكثر صعوبة مما يستحق. مجرد استخدام C ++ إذا كنت تريد أن تفعل هذا ...

ويجب عليك أيضا قراءة ليبمان "داخل وC ++ طراز كائن " الذي يذهب الى التفاصيل المروعة حول كيفية C ++ تعمل وراء الكواليس، في كثير من الأحيان مع قصاصات من كيفية عمل الأشياء في C.


وأعتقد أن أرى ما كنت بعد. ربما.

وكيف يمكن لشيء مثل هذا العمل:

typedef 
struct foo {
    int a;
} foo;

void doSomething( foo f);   // note: f is passed by value

typedef
struct bar {
    foo base;
    int b;
} bar;


int main() {
    bar b = { { 1 }, 2};

    doSomething( b);    // how can the compiler know to 'slice' b
                        //  down to a foo?

    return 0;
}

وحسنا أنك لا تستطيع أن تفعل ذلك ببساطة لأن ذلك من دون دعم اللغة - كنت بحاجة للقيام ببعض الأشياء يدويا (وهذا ما يعني أنها ليست لديها دعم اللغة):

    doSomething( b.base);       // this works

نصائح أخرى

وأساسا، البنيات، داخل البنيات.

struct Base {
    int blah;
};

struct Derived {
    struct Base __base;
    int foo;
};

وعندما تريد، مثلا، يلقي Derived * إلى Base *، وكنت فعلا إرجاع مؤشر إلى العنصر __base من البنية مشتقة، وهو في هذه الحالة هو أول شيء في البنية ذلك مؤشرات يجب أن تكون هي نفسها (لن يكون هذا هو الحال في الفصول التي ورثت متعددة على الرغم من).

إذا كنت ترغب في الوصول blah في هذه الحالة، عليك أن تفعل شيئا من هذا القبيل derived.__base.blah.

عادة ما يتم القيام به

وظائف افتراضية مع جدول خاص للمؤشرات الدالة التي هي جزء من كل كائن، وهو نوع بدائي من "ما هو نوع بي" السجل.

وهنا هو كيف COM يفعل للغة C. أنا صدئ قليلا في هذا، ولكن جوهر يعمل مثل هذا. كل المتغيرات عضو "الطبقة" هو مجرد البنية.

struct Shape
{
  int value;
};

struct Square
{
  struct Shape shape; // make sure this is on top, if not KABOOM
  int someothervalue;
};

وجميع الأساليب، هي في الواقع مجرد وظائف عادية. مثل هذا

void Draw(Shape * shape,int x,int y)
{
  shape->value=10; // this should work even if you put in a square. i think...
}

وبعد ذلك، فإنها تستخدم المعالج إلى "خدعة" رمز C إلى عرض شيء من هذا القبيل.

Square * square;
square->Draw(0,0); // this doesnt make sense, the preprocessor changes it to Draw(square,0,0);

للأسف، أنا لا أعرف أي نوع من الحيل المعالج يتم القيام به لجعل C ++ تبحث عزم استدعاء دالة إلى مكالمة خطة الفانيليا C.

وأعلن

التحف دايركت COM بهذه الطريقة.

د. كان في Dobb مقال مفصل معتدلة حول هذا الموضوع، فئات الميراث واحدة في C.

والبنيات داخل-البنيات هو شائع، ولكنه يجعل من الألم للوصول إلى حقول الموروثة. تحتاج إما إلى استخدام المراوغة (مثل child->parent.field)، أو صب (((PARENT *) child)->field).

وبديل لقد رأيت أكثر من هذا القبيل:

#define COUNTRY_FIELDS \
    char *name; \
    int population;

typedef struct COUNTRY
{
    COUNTRY_FIELDS
} COUNTRY;

#define PRINCIPALITY_FIELDS \
    COUNTRY_FIELDS \
    char *prince;

typedef struct PRINCIPALITY
{
    PRINCIPALITY_FIELDS
} PRINCIPALITY;

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

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

إذا كنت ترغب في إشارة جيدة عن الكيفية التي تأخذ هذه الأعمال الاشياء نظرة على جدك / جتك المكتبات سطحي / مفتوحة المصدر. لديهم وثائق جيدة جدا ويستند الإطار بالكامل على C OO.

ويمكنك محاكاة كائن كتابة الصانعين، وواضعي، حاصل، و destructors مع هذا المؤشر ينادي صراحة المخفية.

ويتم التعامل مع الإرث عن طريق الحصول على كائن اشتقاق تشمل مؤشر إلى كائن قاعدة في بنية الكائن المشتقة.

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