في مشكلة الماس في c++ ، لماذا نحتاج إلى استدعاء مُنشئ grand_parent من فئة تابعة؟




inheritance constructor (2)

الوراثة virtual في التسلسل الهرمي الخاص بك يختفي وجود الفئة الأساسية one خلال التأكد من أن يتم تخزين مثيل واحد واحد فقط في فئات فرعية من two أو three . تذكر أنه عند وراثة فئة ما ، فإن مثيلًا مشتقًا سيخزن دائمًا مثيلًا أساسيًا في مكان ما - داخليًا - لذا فإن الوراثة virtual تضمن أن مثيلات one داخل two three يتم تجاوزها" إلى حد ما من قبل أي فئة أخرى إلى أسفل التسلسل الهرمي للميراث.

والسؤال الآن هو: من المسؤول عن تهيئة هذه الحالة الفردية؟ يجب أن يكون two أو three ؟ بوضوح ليس كلاهما ، حيث لا يوجد سوى مثيل واحد. وهنا أنت: إنها دائمًا الفئة الأكثر اشتقاقًا والمسؤولة عن تهيئة one - وهذا أمر منطقي: يجب على المثيل الذي يضم نسخة من الفئة الأساسية أن يهيئها.

هذه هي الطريقة التي يبدو بها التسلسل الهرمي للفئة مع مثيلات الفئة الأساسية المدمجة بدون four ومع four وراثة virtual :

              +----------+                           +----------+
              |   one    |                           |   one    |
              +----+-----+                           +----+-----+
                   |                                      |
                   |                                      |
         +-------+-----------+           virtual +--------+--------+ virtual
         |                   |                   |                 |
         |                   |                   |                 |
+--------+-------+   +-------+-------+      +----+----+       +----+----+
|      two       |   |      three    |      |  two    |       |  three  |
| +------------+ |   | +----------+  |      +----+----+       +----+----+
| |   one      | |   | |   one    |  |           |                 |
| +------------+ |   | +----------+  |           +--------+--------+
|  => must init! |   | => must init! |                    |
+----------------+   +---------------+            +-------+--------+
                                                  |     four       |
                                                  | +------------+ |
                                                  | |    one     | |
                                                  | +------------+ |
                                                  | => must init!  |
                                                  +----------------+

يمكنك التفكير في هذه الآلية بهذه الطريقة: الميراث virtual يمنح مثيل فئة أساسية virtual ، ويشمل ذلك إنشاء المثيل - تنتقل هذه المسؤولية إلى التسلسل الهرمي.

يرجى قراءة الكود لفهم الموقف.

#include <iostream>
using namespace std;
class one
{
protected:
    int x;
public:
    one(int a)
    {
        x=a;
        cout << "one cons called\n";
    }
    void display(void)
    {
        cout << "x = " << x << endl;
    }
    ~one()
    {
        cout << "one destroy\n";
    }
};
class two : virtual protected one
{
protected:
    int y;
public:
    two(int a,int b) : one(a),y(b)
    {
        cout << "two cons called\n";
    }
    void display(void)
    {
        one::display();
        cout << "y = " << y << endl;
    }
    ~two()
    {
        cout << "two destroy\n";
    }
};

class three : protected virtual one
{
protected:
    int z;
public:
    three(int a,int b) : one(a),z(b)
    {
        cout << "Three cons called\n";
    }
    void display(void)
    {
        one::display();
        cout << "z = " << z << endl;
    }
    ~three()
    {
        cout << "three destroy\n";
    }
};

class four : private two, private three
{
public:
    four(int a,int b,int c) :one(a), two(a,b),three(a,c)
    {
        cout << " four cons called\n";
    }
    void display(void)
    {
        one::display();
        cout << "y = " << y << endl;
        cout << "z = " << z << endl;
    }
    ~four()
    {
        cout << "four destroy\n";
    }
};
int main()
{
    four ob(1,2,3);
    ob.display();
    return 0;
}

إذا قمت باستبدال الرمز

four(int a,int b,int c) :one(a), two(a,b),three(a,c)

مع

four(int a,int b,int c) :two(a,b),three(a,c)

تظهر رسالة خطأ مثل: لا توجد وظيفة مطابقة لاستدعاء "one :: one ()" في كودبلود بلدي.

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


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





diamond-problem