سؤال

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

class A
{
    protected:
        A(){}
};

class B: public A {
    public:
        B() {
            A* f=new A();           // Why it is not working here
        }
};
هل كانت مفيدة؟

المحلول

هذا لا علاقة له بالمشاركات على وجه التحديد. هذا هو كيف protected أعمال الوصول.

الطريقة protected يعمل محدد الوصول ، فهو يسمح للفئة المشتقة B للوصول إلى محتويات كائن من الفئة الأساسية A فقط عندما يكون هذا الكائن من الفصل A هو كائن فرعي للطبقة B. هذا يعني أن الشيء الوحيد الذي يمكنك القيام به في الكود الخاص بك هو الوصول إلى محتويات A عبر B: يمكنك الوصول إلى أعضاء A من خلال مؤشر من النوع B * (أو مرجع من النوع B &). لكنك لا تستطيع الوصول إلى نفس الأعضاء من خلال مؤشر من النوع A * (أو المرجع A &).

النظر في المثال التالي

class A {
protected:
  int i;
};

class B : A  {
  void foo() {
    i = 0;        // OK
    this->i = 0;  // OK

    B *pb = this;
    pb->i = 0;    // OK

    A *pa = this;
    pa->i = 0;    // ERROR

    ((A *) this)->i = 0; // ERROR
  }
};

في ما سبق B::foo, ، يمكنك الوصول إلى عضو الأساس A::i باستخدام سهل فقط i بناء الجملة. هذا يعادل استخدام this->i بناء الجملة. كلاهما سيعمل ، لأن المؤشر this لديه النوع B *, ، أي أنك تصل A::i شامل مؤشر من النوع B *. هذا هو بالضبط ما protected من المفترض أن يسمح محدد الوصول. الوصول من خلال pb المؤشر يعمل لنفس السبب.

ومع ذلك ، عند "تحويل" this مؤشر للكتابة A *, ، لم يعد بإمكانك الوصول A::i من خلال هذا المؤشر الجديد ، على الرغم من أنك لا تزال تحاول الوصول إلى نفس العضو كما كان من قبل.

عند تطبيقها على المُنشئين ، protected يحتوي محدد الوصول على تأثير محدد للغاية: لا يمكن استخدام مُنشئ محمي إلا لتهيئة المشروعات الفرعية من الفئة الأساسية. لا يمكن استخدامه لتهيئة الكائنات المستقلة (وهو ما كنت تحاول القيام به). بمعنى آخر ، فإن المُنشئين المحميين هم طريقة أخرى لتنفيذ مفهوم فئة مجردة في C ++ (جنبا إلى جنب مع الأساليب الافتراضية النقية). إذا كانت مُنشئو فصلك محميين ، فسيكون فصلك بفعالية نبذة مختصرة. لا يمكنك استخدامه لتحديد الكائنات المستقلة "من الخارج". (بالطبع ، لا ينطبق ما ورد أعلاه داخل الأصدقاء ، وكذلك داخل الفصل نفسه).

نصائح أخرى

عندما يكون لدى الفئة الأساسية مُنشئًا محميًا ، لا يمكنك إنشاء إنشاء الفصل مباشرة. ولكن يمكنك القيام بذلك لاستدعاء المُنشئ من مُنشئ الفئة الأساسية:

class A {

protected:
   A() {}
};

class B: public A {
public:
   B() : A() // allowed to access constructor like this
   {
      A* f = new A(); // Not allowed to access constructor like this!
   }
};

تمنحك مكالمة مباشرة إلى المُنشئ كما هو موضح أدناه الخطأ التالي مع الإصدار 4.1.2:

      A* f = new A(); // Not allowed to access constructor like this!

test.cpp:4: error: A::A() is protected

ومع ذلك ، فإنك هذه الدعوة إلى المنشئ لا تعطي أي أخطاء:

   B() : A() // allowed to access constructor like this

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

      A* f = new A(); // Not allowed to access constructor like this!

قد يبدو هذا غير بديهي ، حيث يجب أن يكون B قادرًا على الوصول إلى مُنشئ A لأن B يرث من A. ومع ذلك ، إذا أعلنت منشئًا محمي في C ++ ، لا يمكنك إنشاء مثيل لتلك الفئة إلا من خلال الميراث أو علاقة صديق.

اسمحوا لي أن أضع إجابتي في الخطوات:

1) لا يتم الوراثة من البنائين ولهذا السبب في الطبقة المشتقة ، لا يمكن أن يكونوا أكثر من ذلك.
2) يتم استدعاء البنائين ولا يسمى.
3) إذا كنت قد أعلنت وظيفة بسيطة في print void محمية () ثم حاولت الاتصال بها في B ، لكان قد نجحت. هذا يحدث BCOZ ، B قد ورث هذه الوظيفة.

4) عندما تفعل شيئًا مثل هذا B: A () ، فأنت تستدعي المُنشئ وهذا مسموح به.
5) حاول جعل ب فئة صديق من A ثم قم بالتشغيل ومعرفة ما إذا كان يعمل.

أتمنى أن يساعدك هذا.

كان لدي نفس السؤال مثل هذا ، و هذا الرابط اجعلني واضحا.

cppreference يقول مثل هذا:

Protected members form the interface for the derived classes (which is   

distinct from the public interface of the class). 

A protected member of a class Base can only be accessed 

1) by the members and friends of Base 

2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top