لماذا لا يمكن الوصول إلى عضو الفئة الفائقة المحمية في وظيفة الفئة الفرعية عند تمريرها كوسيطة؟

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

سؤال

أحصل على خطأ في التجميع ، وأنا مرتبك قليلاً. هذا على VS2003.

خطأ C2248: 'a :: y': لا يمكن الوصول إلى العضو المحمي المعلن في الفصل "أ"

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

المشكلة هي مع x = item.y ؛

يتم تحديد الوصول على أنه محمي. لماذا لا يستطيع مُنشئ الفئة ب الوصول إلى :: y؟

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

المحلول

هذا بسبب هذا:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

إذا كان ذلك قانونيًا ، فيمكنك القيام بذلك:

A a;
B b;
b.bar(&a);

وستتصل protected عضو من A من B ، وهو أمر غير مسموح به.

نصائح أخرى

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

ومع ذلك ، قد تقرر أن هذا غير مناسب (أو قد لا يكون لديك سيطرة على تعريف A). فيما يلي بعض الاقتراحات للسماح لك بالتنقل حول المشكلة ، بترتيب متزايد من الخضوع Aالتحكم في الوصول. لاحظ أن كل هذه الحلول تفترض ذلك class A يمكن نسخه.

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

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

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

المثال التالي يخلق مؤقتًا B الكائن الذي يحتوي على نسخ دقيق من A كائن نريد الوصول إليه. يمكننا بعد ذلك استخدام المؤقتة B كائن للوصول إلى العناصر التي كانت محمية:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

أجد أن هذا الحل أقل إرباكًا قليلاً من الأول ، لكنه لا يزال مربكًا (في رأيي). إن وجود نسخة من الكائن B من B Comple فقط للوصول إلى أجزاء الكائن الذي نريده أمر غريب.

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

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};

تلخص وثائق IBM بشكل أفضل:

يمكن الوصول إلى عضو فئة قاعدة محمية غير مستقر من قبل الأعضاء والأصدقاء في أي فصول مستمدة من تلك الفئة الأساسية باستخدام أحد ما يلي:

  • مؤشر إلى فئة مشتقة بشكل مباشر أو غير مباشر
  • إشارة إلى فئة مشتقة بشكل مباشر أو غير مباشر
  • كائن فئة مشتقة بشكل مباشر أو غير مباشر

وبالتالي ، باستخدام مثالك أعلاه كأساس:

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top