سؤال

ماهو الفرق بين public, private, ، و protected الميراث في C++؟جميع الأسئلة التي وجدتها في SO تتعامل مع حالات محددة.

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

المحلول

للإجابة على هذا السؤال، أود أن أصف أدوات وصول الأعضاء أولاً بكلماتي الخاصة.إذا كنت تعرف هذا بالفعل، فانتقل إلى العنوان "التالي:".

هناك ثلاثة وصول أنا على علم بها: public, protected و private.

يترك:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • كل ما يعلم Base ويدرك ذلك أيضا Base يتضمن publicMember.
  • فقط الأطفال (وأطفالهم) يدركون ذلك Base يتضمن protectedMember.
  • لا أحد سوى Base على بينة من privateMember.

أعني بـ "يدرك" "الاعتراف بوجود، وبالتالي القدرة على الوصول إليه".

التالي:

ويحدث الشيء نفسه مع الميراث العام والخاص والمحمي.دعونا نفكر في الفصل الدراسي Base وفئة Child الذي يرث من Base.

  • إذا كان الميراث public, ، كل ما هو على علم Base و Child ويدرك ذلك أيضا Child يرث من Base.
  • إذا كان الميراث protected, ، فقط Child, ، وأبناؤها، يعلمون أنهم يرثون منها Base.
  • إذا كان الميراث private, ، لا أحد غير Child يعرف الميراث.

نصائح أخرى

class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

ملاحظة هامة: فئات B، C و D تحتوي على جميع المتغيرات x و y و z. ومن السؤال العادل من الوصول.

وعن استخدام الميراث المحمية والخاص هل يمكن قراءة هنا .

سيؤدي الحد من رؤية الوراثة إلى جعل الكود غير قادر على رؤية أن بعض الفئات ترث فئة أخرى:لن تعمل التحويلات الضمنية من المشتقة إلى القاعدة، و static_cast من القاعدة إلى المشتقة لن تعمل أيضًا.

يمكن فقط لأعضاء/أصدقاء الفصل رؤية الميراث الخاص، ويمكن فقط للأعضاء/الأصدقاء والفئات المشتقة رؤية الميراث المحمي.

عام ميراث

  1. IS-ميراث.الزر عبارة عن نافذة، وفي أي مكان حيث تكون هناك حاجة إلى نافذة، يمكن تمرير زر أيضًا.

    class button : public window { };
    

محمي ميراث

  1. المحمية المنفذة من حيث.نادرا ما تكون مفيدة.مستعمل في boost::compressed_pair للاشتقاق من الفئات الفارغة وحفظ الذاكرة باستخدام تحسين الفئة الأساسية الفارغة (المثال أدناه لا يستخدم القالب ليظل في صلب الموضوع):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

خاص ميراث

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

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

عام عضو

  1. إجمالي

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. الملحقات

    class window {
    public:
        int getWidth() const;
    };
    

محمي عضو

  1. توفير الوصول المحسن للفئات المشتقة

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

خاص عضو

  1. احتفظ بتفاصيل التنفيذ

    class window {
    private:
      int width;
    };
    

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

يتعلق الأمر بكيفية تعرض الأعضاء العامين للفئة الأساسية من الفئة المشتقة.

  • عام -> سيكون الأعضاء العامون للفئة الأساسية علنيين (عادةً ما يكونون الافتراضيين)
  • محمي -> سيتم حماية الأعضاء العامين في الفئة الأساسية
  • خاص -> سيكون الأعضاء العامون في الفئة الأساسية خاصين

كما يشير litb، الميراث العام هو الميراث التقليدي الذي ستراه في معظم لغات البرمجة.وهذا يعني أنها تمثل علاقة "IS-A".الميراث الخاص، وهو أمر خاص بـ AFAIK لـ C++، هو علاقة "يتم تنفيذها من حيث".هذا هو ما تريد يستخدم الواجهة العامة في الفئة المشتقة، ولكن لا تريد أن يتمكن مستخدم الفئة المشتقة من الوصول إلى تلك الواجهة.يجادل الكثيرون بأنه في هذه الحالة يجب عليك تجميع الفئة الأساسية، أي بدلاً من جعل الفئة الأساسية كقاعدة خاصة، قم بإنشاء عضو مشتق من أجل إعادة استخدام وظائف الفئة الأساسية.

تُستخدم هذه الكلمات الرئيسية الثلاث أيضًا في سياق مختلف تمامًا لتحديد نموذج وراثة الرؤية.

يجمع هذا الجدول كل المجموعات الممكنة لإعلان المكون ونموذج الميراث الذي يعرض الوصول الناتج إلى المكونات عندما يتم تعريف الفئة الفرعية بالكامل.

enter image description here

يتم تفسير الجدول أعلاه بالطريقة التالية (ألق نظرة على الصف الأول):

إذا كان أحد المكونات أعلن مثل عام وفئته هي وارث مثل عام النتيجة وصول يكون عام.

مثال:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

الوصول الناتج للمتغيرات p, q, r في الفصل فرعي يكون لا أحد.

مثال آخر:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

الوصول الناتج للمتغيرات y, z في الفصل الفرعية يكون محمي و للمتغير x يكون لا أحد.

مثال أكثر تفصيلا:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

الآن دعونا نحدد فئة فرعية:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

الفئة المحددة المسماة Sub وهي فئة فرعية من الفئة المسماة Super أو ذلك Sub الطبقة مشتقة من Super فصل.ال Sub لا يقدم الفصل متغيرات جديدة ولا وظائف جديدة.هل يعني ذلك أن أي كائن من Sub يرث الفصل جميع السمات بعد Super الطبقة هي في الواقع نسخة من أ Super كائنات الطبقة؟

لا.لا.

إذا قمنا بتجميع الكود التالي، فلن نحصل على شيء سوى أخطاء التجميع التي تقول ذلك put و get الأساليب لا يمكن الوصول إليها.لماذا؟

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

يتعين علينا إبلاغ المترجم بأننا نريد الحفاظ على سياسة الوصول المستخدمة مسبقًا.

class Sub : public Super { };

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

كائنات ال Sub قد يفعل الفصل "تقريبًا" نفس الأشياء التي قام بها إخوتهم الأكبر سنًا الذين تم إنشاؤهم من Super فصل. "بالكاد" لأن حقيقة كونها فئة فرعية تعني أيضًا أن فقدت الطبقة الوصول إلى المكونات الخاصة للفئة المتفوقة.لا يمكننا كتابة وظيفة عضو في Sub فئة والتي ستكون قادرة على التعامل مباشرة مع متغير التخزين.

وهذا تقييد خطير للغاية.هل هناك أي عمل في الأرجاء؟

نعم.

يسمى مستوى الوصول الثالث محمي.الكلمة الأساسية المحمية تعني أن المكون المميز بها تتصرف كفئة عامة عند استخدامها من قبل أي من الفئات الفرعية وتبدو وكأنها فئة خاصة لبقية العالم. -- ينطبق هذا فقط على الفئات الموروثة علنًا (مثل الفئة Super في مثالنا) --

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

كما ترون في رمز المثال لدينا وظيفة جديدة ل Sub الفصل ويفعل شيئًا مهمًا: يصل إلى متغير التخزين من فئة Super.

لن يكون ذلك ممكنًا إذا تم الإعلان عن المتغير على أنه خاص.في نطاق الوظيفة الرئيسية، يظل المتغير مخفيًا على أي حال، لذا إذا كتبت شيئًا مثل:

object.storage = 0;

سيخبرك المترجم أنه error: 'int Super::storage' is protected.

وأخيرًا، سينتج البرنامج الأخير المخرجات التالية:

storage = 101
Member in base class : Private   Protected   Public   

<القوي> نوع الوراثة : ل<القوي> كائن رثت ك : ل

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

1) الميراث العام:

أ.لا يمكن الوصول إلى الأعضاء الخاصين في الفئة الأساسية في الفئة المشتقة.

ب.يظل الأعضاء المحميون من الفئة الأساسية محميين في الفئة المشتقة.

ج.يظل الأعضاء العامون في الفئة الأساسية عامًا في الفئة المشتقة.

لذلك، يمكن للفئات الأخرى استخدام الأعضاء العامين للفئة الأساسية من خلال كائن الفئة المشتقة.

2) الميراث المحمي:

أ.لا يمكن الوصول إلى الأعضاء الخاصين في الفئة الأساسية في الفئة المشتقة.

ب.يظل الأعضاء المحميون من الفئة الأساسية محميين في الفئة المشتقة.

ج.يصبح الأعضاء العامون في الفئة الأساسية أيضًا أعضاء محميين في الفئة المشتقة.

لذلك، لا يمكن للفئات الأخرى استخدام الأعضاء العامين للفئة الأساسية من خلال كائن الفئة المشتقة؛لكنها متاحة لفئة فرعية من المشتقة.

3) الميراث الخاص:

أ.لا يمكن الوصول إلى الأعضاء الخاصين في الفئة الأساسية في الفئة المشتقة.

ب.يصبح الأعضاء المحميون والعامة من الفئة الأساسية أعضاء خاصين من الفئة المشتقة.

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

ونماذج الميراث العام لIS-A العلاقة. مع

class B {};
class D : public B {};

وكل D <م> هو B.

ونماذج الميراث الخاص لIS-المنفذة باستخدام العلاقة (أو أيا كان يسمى). مع

class B {};
class D : private B {};

وعلى D هو لا وB، ولكن كل D يستخدم B في تنفيذه. الميراث الخاص يمكن دائما القضاء باستخدام الاحتواء بدلا من ذلك:

class B {};
class D {
  private: 
    B b_;
};

وهذا D، أيضا، يمكن تنفيذها باستخدام B، في هذه الحالة باستخدام b_ لها. الاحتواء هو اقتران أقل ضيق بين أنواع من الميراث، وذلك في عام فإنه ينبغي تفضيل. في بعض الأحيان باستخدام الاحتواء بدلا من الميراث الخاص ليست مريحة مثل الميراث الخاص. في كثير من الأحيان وهذا هو حجة واهية لكونه كسول.

وأنا لا أعتقد أن أحدا يعرف ما protected نماذج الميراث. على الأقل أنا لم أر أي تفسير مقنع حتى الان.

إذا ورثت علنًا من فئة أخرى، يعلم الجميع أنك ترث ويمكن لأي شخص أن يستخدمك بشكل متعدد الأشكال من خلال مؤشر الفئة الأساسية.

إذا ورثت بشكل محمي، فلن تتمكن سوى فصول أطفالك من استخدامك بشكل متعدد الأشكال.

إذا ورثت بشكل خاص، فلن تتمكن سوى نفسك من تنفيذ أساليب الفئة الأصل.

والذي يرمز بشكل أساسي إلى المعرفة التي تمتلكها بقية الفصول حول علاقتك مع صفك الأم

وأعضاء البيانات المحمية يمكن الوصول إليها من قبل أي الفئات التي ترث من الفئة الخاصة بك. أعضاء البيانات الخاصة، ومع ذلك، لا يمكن. دعونا نقول لدينا ما يلي:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

ومن داخل تمديد لهذه الفئة، والرجوع this.myPrivateMember لا تعمل. ومع ذلك، سوف this.myProtectedMember. لا تزال مغلفة قيمة، لذلك إذا كان لدينا مثيل من هذه الفئة يسمى myObj، ثم myObj.myProtectedMember لن تنجح، لذلك هو مماثل في وظيفة لعضو بيانات الخاص.

Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

وبناء على هذا سبيل المثال لجافا ... وأعتقد طاولة صغيرة تساوي ألف كلمة:)

ملخص:

  • خاص:ولا يمكن لأحد رؤيته إلا داخل الفصل
  • محمي:يمكن للفصول الخاصة + المشتقة رؤيتها
  • عام:يمكن للعالم رؤيته

عند الوراثة، يمكنك (في بعض اللغات) تغيير نوع الحماية لعضو البيانات في اتجاه معين، على سبيل المثال.من المحمية إلى العامة.

خاص:

ويمكن فقط الوصول إلى أعضاء القطاع الخاص من فئة أساسية من أعضاء تلك الفئة الأساسية.

العامة:

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

المحمية:

ويمكن الوصول إلى أعضاء المحمية من الفئة الأساسية من قبل أفراد من الفئة الأساسية فضلا عن أعضاء من الدرجة المشتقة منها.


باختصار:

<قوية> خاصة : في قاعدة

<قوية> محمية : في قاعدة + المستمدة

<قوية> العامة : لقاعدة + المستمدة + أي عضو آخر

ولقد وجدت إجابة سهلة وهكذا فكرت في نشرها لتكون مرجعا مستقبلي أيضا.

ولها من الروابط HTTP: //www.learncpp كوم / حزب الشعب الكمبودي البرنامج التعليمي / 115 الوراثة وصول المختصين /

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

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

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