ความแตกต่างระหว่างการสืบทอดส่วนบุคคลสาธารณะและการป้องกัน


คำตอบ:


1064

เพื่อตอบคำถามนั้นฉันต้องการอธิบาย accessors ของสมาชิกก่อนด้วยคำพูดของตัวเอง หากคุณรู้สิ่งนี้แล้วให้ข้ามไปที่หัวข้อ "ถัดไป:"

มีสาม accessors ว่าฉันรู้คือpublic, protectedและprivateและ

ปล่อย:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • ทุกสิ่งที่รับทราบBaseก็เป็นสิ่งที่BaseมีpublicMemberอยู่เช่นกัน
  • เฉพาะเด็ก (และเด็กของพวกเขา) จะทราบว่ามีBaseprotectedMember
  • ไม่มีใครBaseรู้privateMemberนอกจาก

โดย "ตระหนักถึง" ฉันหมายถึง "ยอมรับการมีอยู่ของและสามารถเข้าถึงได้"

ต่อไป:

สิ่งเดียวกันนี้เกิดขึ้นกับการสืบทอดมรดกที่เป็นสาธารณะและเป็นส่วนตัว ลองพิจารณาชั้นBaseและชั้นเรียนที่สืบทอดจากChildBase

  • ถ้าได้รับมรดกเป็นpublicทุกอย่างที่ตระหนักถึงBaseและChildยังเป็นที่ทราบว่าสืบทอดมาจากChildBase
  • หากเป็นมรดกprotectedเท่านั้นChildและลูกของมันจะรู้ว่าพวกเขาสืบทอดมาจากBaseและเด็กที่มีความตระหนักว่าพวกเขาได้รับมรดกจาก
  • หากการสืบทอดเป็นมรดกจะprivateไม่มีใครอื่นนอกจากการChildรับรู้ถึงมรดก

182
ฉันต้องการเพิ่มคำสองสามคำที่การมองเห็นใน C ++ ขึ้นอยู่กับคลาสแทนที่จะเป็นบนวัตถุซึ่งหมายความว่าวัตถุของคลาสเดียวกันสามารถเข้าถึงฟิลด์ส่วนตัวของกันและกันได้โดยไม่มีข้อ จำกัด
Zhe Chen

48
หากคุณมีปัญหาในการทำความเข้าใจนี้อ่านคำตอบของคิริลล์วี. Lyadvinsky แล้วกลับมาอ่านอีกครั้ง
Vivandiere

6
นี่เป็นเพียงอีกกรณีหนึ่งที่แสดงให้เห็นว่าส่วนใหญ่ที่สืบทอดจากเป็นเช่นเดียวกับวิธีการเขียนแบบฮาร์ดโค้ดในสมาชิกที่ไม่ระบุชื่อประเภทSomeBase SomeBaseสิ่งนี้ก็เหมือนกับสมาชิกคนอื่น ๆ ที่มีตัวระบุการเข้าถึงซึ่งใช้ตัวควบคุมเดียวกันกับการเข้าถึงภายนอก
underscore_d

1
@ZheChen ถ้าฉันมีวัตถุ Tom and Jerry ของคลาสบุคคลที่มีฟิลด์อายุส่วนตัวคุณจะเข้าถึง (และแก้ไขได้อย่างไร) อายุของ Jerry โดยใช้ Tom?
Gen

2
คุณสามารถอธิบายสิ่งที่คุณหมายถึงโดย "ตระหนักถึง 'มรดก'"? ฉันสามารถเข้าใจ "ฉันสามารถเข้าถึงสิ่งนี้ได้ฉันไม่สามารถเข้าถึงสิ่งนั้นได้" แต่ฉันไม่ได้รับเมื่อมีคนบอกว่า "ฉันรู้ว่า A สืบทอดมาจาก B" ฉันกำลังทำอะไรที่นี่ฉันกำลังตรวจสอบมรดกอยู่หรือไม่
neilxdims

1458
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 มันเป็นเพียงคำถามของการเข้าถึง

การใช้งานเกี่ยวกับการคุ้มครองและมรดกส่วนตัวที่คุณสามารถอ่านได้ที่นี่


35
สิ่งที่ Anzurio เขียนเพียงคลิกร่วมกับคำตอบของคุณทันทีด้านล่าง วันที่ 1
Iwillnotexist Idonotexist

2
ความเข้าใจของฉันเกี่ยวกับวิธีการทำงานนี้ได้ไกลมาก! ขอบคุณมากสำหรับการชี้แจง
tjwrona1992

ฉันใช้เวลาพอสมควรที่จะเข้าใจสิ่งนี้ แต่ตอนนี้มันชัดเจน ขอบคุณ!
Chan Kim

115

การ จำกัด การเปิดเผยของการสืบทอดจะทำให้โค้ดไม่สามารถมองเห็นได้ว่าบางคลาสสืบทอดคลาสอื่น: การแปลงโดยนัยจากที่ได้รับไปยังฐานจะไม่ทำงานและ static_castจากฐานไปยังที่ได้รับมาจะไม่ทำงาน

มีเพียงสมาชิก / เพื่อนของคลาสเท่านั้นที่สามารถเห็นการสืบทอดส่วนตัวและเฉพาะสมาชิก / เพื่อนและคลาสที่ได้รับเท่านั้นที่สามารถดูการสืบทอดที่ได้รับการป้องกันได้

มรดกสาธารณะ

  1. เป็นมรดก ปุ่มคือหน้าต่างและที่ใดก็ได้ที่ต้องการหน้าต่างก็สามารถส่งปุ่มได้เช่นกัน

    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. accessors

    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-style casts อนุญาตให้ทำการแคสต์คลาสที่ได้รับไปยังคลาสฐานที่ได้รับการปกป้องหรือเป็นส่วนตัวในลักษณะที่กำหนดและปลอดภัย สิ่งนี้ควรหลีกเลี่ยงค่าใช้จ่ายทั้งหมดเนื่องจากสามารถทำให้รหัสขึ้นอยู่กับรายละเอียดการใช้งาน - แต่ถ้าจำเป็นคุณสามารถใช้เทคนิคนี้ได้


7
ฉันคิดว่า Scott Myers (เท่าที่ฉันชอบสิ่งที่เขา) มีจำนวนมากที่จะตอบสนองต่อความสับสนทั่วไป ตอนนี้ฉันคิดว่าการเปรียบเทียบของเขากับ IS-A และ IS-IMPLEMENTED-IN-TERMS-OF นั้นเพียงพอแล้วสำหรับสิ่งที่เกิดขึ้น
DangerMouse

65

คำหลักสามคำนี้ยังใช้ในบริบทที่แตกต่างอย่างสิ้นเชิงเพื่อระบุรูปแบบการสืบทอดการมองเห็นรูปแบบการมองเห็นการรับมรดก

ตารางนี้รวบรวมชุดค่าผสมที่เป็นไปได้ทั้งหมดของการประกาศส่วนประกอบและโมเดลการสืบทอดที่แสดงการเข้าถึงผลลัพธ์ไปยังคอมโพเนนต์เมื่อกำหนดคลาสย่อยอย่างสมบูรณ์

ป้อนคำอธิบายรูปภาพที่นี่

ตารางข้างต้นถูกตีความด้วยวิธีดังต่อไปนี้ (ดูที่แถวแรก):

ถ้าเป็นส่วนประกอบจะมีการประกาศให้เป็นสาธารณะและระดับนี้จะได้รับมรดกในฐานะประชาชนที่เกิดการเข้าถึงเป็นสาธารณะ

ตัวอย่าง:

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

 class Sub : private Super {};

 class Subsub : public Sub {};

ส่งผลให้การเข้าถึงสำหรับตัวแปรp, q, rในชั้นเรียนSubsubเป็นใคร

ตัวอย่างอื่น:

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 { };

อย่าหลงผิด : ไม่ได้หมายความว่าส่วนประกอบส่วนตัวของคลาส Super (เช่นตัวแปรหน่วยเก็บข้อมูล) จะเปลี่ยนเป็นสาธารณะในลักษณะที่น่าอัศจรรย์ เอกชนส่วนประกอบจะยังคงเอกชน , ประชาชน จะยังคงอยู่ของประชาชน

วัตถุในSubชั้นเรียนอาจทำสิ่งเดียวกันกับพี่น้องที่สร้างขึ้นจากSuperชั้นเรียน "เกือบ"เพราะความเป็นจริงของการเป็นประเภทรองยังหมายถึงว่าการเข้าถึงชั้นหายไปส่วนประกอบส่วนตัวของซับคลาส เราไม่สามารถเขียนฟังก์ชันสมาชิกของSubคลาสซึ่งจะสามารถจัดการตัวแปรหน่วยเก็บข้อมูลได้โดยตรง

นี่เป็นข้อ จำกัด ที่ร้ายแรงมาก มีวิธีแก้ปัญหาหรือไม่?

ใช่แล้ว

ระดับการเข้าถึงที่สามเรียกว่าได้รับการคุ้มครอง คำหลักที่มีการป้องกันหมายความว่าองค์ประกอบที่มีเครื่องหมายมันทำงานเหมือนประชาชนคนหนึ่งเมื่อนำมาใช้โดยการใด ๆ ของ subclasses และรูปลักษณ์ที่เหมือนส่วนตัวกับส่วนที่เหลือของโลก - สิ่งนี้เป็นจริงสำหรับคลาสที่สืบทอดสู่สาธารณะเท่านั้น (เช่นคลาส 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การเรียนและมันไม่สิ่งหนึ่งที่สำคัญ: มันเข้าถึงตัวแปรจัดเก็บจากชั้นซูเปอร์

มันจะเป็นไปไม่ได้ถ้าประกาศตัวแปรเป็นส่วนตัว ในขอบเขตฟังก์ชั่นหลักตัวแปรยังคงซ่อนอยู่ดังนั้นถ้าคุณเขียนอะไรเช่น:

object.storage = 0;

error: 'int Super::storage' is protectedคอมไพเลอร์จะแจ้งให้ทราบว่ามันเป็น

ในที่สุดโปรแกรมสุดท้ายจะสร้างผลลัพธ์ต่อไปนี้:

storage = 101

4
คนแรกที่พูดถึงการขาดตัวดัดแปลง (เช่นเดียวกับใน Class: SuperClass) ให้ผลตอบแทนส่วนตัว นี่เป็นส่วนสำคัญที่คนอื่นขาดหายไปพร้อมกับคำอธิบายอย่างละเอียด +1
น้ำ

2
overkill IMO แต่ฉันชอบโต๊ะที่จุดเริ่มต้น
cp.engr

63

มันเกี่ยวข้องกับวิธีการที่สมาชิกสาธารณะของคลาสฐานนั้นถูกเปิดเผยจากคลาสที่ได้รับมา

  • สาธารณะ -> สมาชิกสาธารณะของคลาสฐานจะเป็นสาธารณะ (โดยปกติจะเป็นค่าเริ่มต้น)
  • ได้รับการป้องกัน -> สมาชิกสาธารณะของคลาสฐานจะได้รับการคุ้มครอง
  • ส่วนตัว -> สมาชิกสาธารณะของคลาสฐานจะเป็นส่วนตัว

ตามที่ litb ชี้ให้เห็นการสืบทอดสาธารณะเป็นมรดกดั้งเดิมที่คุณจะเห็นในภาษาการเขียนโปรแกรมส่วนใหญ่ นั่นคือแบบจำลองความสัมพันธ์ "IS-A" การรับมรดกส่วนตัวสิ่งที่แปลกประหลาดกับ C ++ คือความสัมพันธ์ "ดำเนินการในข้อกำหนดของ" นั่นคือคุณต้องการใช้ส่วนต่อประสานสาธารณะในคลาสที่ได้รับ แต่ไม่ต้องการให้ผู้ใช้ของคลาสที่ได้รับนั้นสามารถเข้าถึงส่วนต่อประสานนั้นได้ หลายคนแย้งว่าในกรณีนี้คุณควรรวมคลาสพื้นฐานนั่นคือแทนที่จะมีคลาสฐานเป็นฐานส่วนตัวให้เป็นสมาชิกของมาเพื่อนำกลับมาใช้ฟังก์ชั่นของชั้นฐาน


13
ควรพูดว่า "สาธารณะ: ทุกคนจะได้รับมรดก" ได้รับการป้องกัน: การสืบทอดจะเห็นได้เฉพาะคลาสที่ได้รับและเพื่อน "," ส่วนตัว: การสืบทอดจะเห็นเฉพาะคลาสและเพื่อน ๆ "ซึ่งแตกต่างจากถ้อยคำของคุณเนื่องจากไม่เพียง แต่สมาชิกจะมองไม่เห็น แต่ยัง ความสัมพันธ์ระหว่าง IS-A จะไม่สามารถมองเห็นได้
Johannes Schaub - litb

4
ครั้งเดียวที่ฉันใช้การสืบทอดแบบส่วนตัวคือทำสิ่งที่ Doug T อธิบายเช่น "คุณต้องการใช้ส่วนต่อประสานสาธารณะในคลาสที่ได้รับ แต่ไม่ต้องการให้ผู้ใช้ของคลาสที่ได้รับนั้นสามารถเข้าถึงส่วนต่อประสานนั้น" โดยทั่วไปฉันใช้มันเพื่อปิดอินเทอร์เฟซเก่าและเปิดเผยอีกอันผ่านคลาสที่ได้รับ
รวย

36
Member in base class : Private   Protected   Public   

ประเภทมรดก :              วัตถุที่รับช่วงเป็น :

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

23
สิ่งนี้ทำให้เข้าใจผิด สมาชิกส่วนบุคคลของคลาสพื้นฐานนั้นมีพฤติกรรมที่แตกต่างจากสมาชิกคลาสส่วนตัวทั่วไป - พวกเขาไม่สามารถเข้าถึงได้จากคลาสที่ได้รับเลย ฉันคิดว่าคอลัมน์ของคุณสาม "ส่วนตัว" ควรเป็นคอลัมน์ของ "ไม่สามารถเข้าถึงได้" ดู Kirill V. Lyadvinsky ตอบคำถามนี้
Sam Kauffman

27

1) มรดกสาธารณะ :

สมาชิกส่วนตัวของคลาสฐานไม่สามารถเข้าถึงได้ในคลาสที่ได้รับ

ข สมาชิกที่ได้รับการป้องกันของคลาสฐานจะได้รับการป้องกันในคลาสที่ได้รับมา

ค. สมาชิกสาธารณะของคลาสฐานยังคงเป็นสาธารณะในคลาสที่ได้รับมา

ดังนั้นคลาสอื่น ๆ สามารถใช้สมาชิกสาธารณะของคลาสฐานผ่านคลาสอ็อบเจ็กต์ที่ได้รับ

2) การป้องกันมรดก :

สมาชิกส่วนตัวของคลาสฐานไม่สามารถเข้าถึงได้ในคลาสที่ได้รับ

ข สมาชิกที่ได้รับการป้องกันของคลาสฐานจะได้รับการป้องกันในคลาสที่ได้รับมา

ค. สมาชิกสาธารณะของคลาสฐานกลายเป็นสมาชิกที่ได้รับการป้องกันของคลาสที่ได้รับมาด้วย

ดังนั้นคลาสอื่นไม่สามารถใช้สมาชิกสาธารณะของคลาสฐานผ่านคลาสอ็อบเจ็กต์ที่ได้รับ แต่จะพร้อมใช้งานกับคลาสย่อยของ Derived

3) มรดกส่วนตัว :

สมาชิกส่วนตัวของคลาสฐานไม่สามารถเข้าถึงได้ในคลาสที่ได้รับ

ข สมาชิกที่ได้รับการป้องกันและสาธารณะของคลาสพื้นฐานจะกลายเป็นสมาชิกส่วนตัวของคลาสที่ได้รับมา

ดังนั้นไม่มีสมาชิกของคลาสฐานที่สามารถเข้าถึงได้โดยคลาสอื่นผ่านวัตถุคลาสที่ได้รับเนื่องจากพวกเขาเป็นส่วนตัวในคลาสที่ได้รับมา ดังนั้นแม้แต่คลาสย่อยของคลาส Derived ก็ไม่สามารถเข้าถึงได้


20

การสืบทอดสาธารณะเป็นแบบจำลองความสัมพันธ์ IS-A กับ

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

ทุกเป็นD B

การรับมรดกส่วนบุคคลเป็นแบบจำลองความสัมพันธ์แบบ IS-IMPLEMENTED-USING (หรือสิ่งที่เรียกว่า) กับ

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

Dคือไม่Bแต่ทุกDใช้มันBในการดำเนินงานของ การสืบทอดส่วนตัวสามารถกำจัดได้โดยใช้การกักกันแทน:

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

นี้Dก็สามารถจะดำเนินการโดยใช้ในกรณีนี้ใช้มันB b_การบรรจุเป็นข้อต่อที่แน่นน้อยกว่าระหว่างชนิดมากกว่าการสืบทอดดังนั้นโดยทั่วไปควรเลือกใช้ บางครั้งการใช้การกักกันแทนการสืบทอดส่วนตัวไม่สะดวกเท่ากับการรับมรดกส่วนตัว บ่อยครั้งที่ข้อแก้ตัวอ่อนแอสำหรับการขี้เกียจ

ฉันไม่คิดว่าใครจะรู้ว่าprotectedแบบจำลองการรับมรดกคืออะไร อย่างน้อยฉันก็ยังไม่เห็นคำอธิบายที่น่าเชื่อถือใด ๆ


บางคนบอกว่าเป็นความสัมพันธ์ ชอบใช้เก้าอี้เป็นค้อน ที่นี่เก้าอี้: ค้อนป้องกัน
user4951

เมื่อใช้การควบคุมแทนที่จะเป็นการรับมรดกแบบส่วนตัวไม่สะดวกเท่ากับการรับมรดกส่วนตัว? คุณช่วยอธิบายด้วยตัวอย่างได้ไหม
Destructor

@Pravasi: ถ้าDบุคลากรเอกชนจากมันสามารถแทนที่การทำงานเสมือนจริงของD B(ถ้ายกตัวอย่างเช่นBเป็นอินเตอร์เฟซผู้สังเกตการณ์แล้วDสามารถใช้มันและผ่านthisฟังก์ชั่นที่กำหนดให้ auch อินเตอร์เฟซโดยไม่ต้องทุกคนจะสามารถใช้Dในฐานะผู้สังเกตการณ์.) นอกจากนี้Dการคัดเลือกจะทำให้สมาชิกของที่มีอยู่ในอินเตอร์เฟซของมันด้วยการทำB using B::memberทั้งสองมีความไม่สะดวกในการใช้ syntactically เมื่อBเป็นสมาชิก
sbi

@sbi: เก่า แต่ ... การกักกันเป็นสิ่งที่ไม่ต้องดำเนินการในกรณีของ CRTP และ / หรือเวอร์ชวล (ตามที่คุณอธิบายไว้อย่างถูกต้องในความคิดเห็น - แต่นั่นหมายความว่ามันไม่สามารถสร้างแบบจำลองเป็นการกักกันได้ถ้า B มีวิธีนามธรรม ไม่อนุญาตให้แตะ) protectedมรดกที่ผมเคยพบว่ามีประโยชน์กับvirtualชั้นฐานและprotectedctor:struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
lorro

11

ถ้าคุณสืบทอดต่อสาธารณะจากคลาสอื่นทุกคนรู้ว่าคุณกำลังสืบทอดและคุณสามารถใช้ polymorphically โดยใครก็ได้ผ่านตัวชี้คลาสพื้นฐาน

หากคุณสืบทอดการป้องกันเพียงชั้นเรียนลูกของคุณจะสามารถใช้คุณ polymorphically

หากคุณสืบทอดโดยส่วนตัวเพียงอย่างเดียวคุณจะสามารถดำเนินการวิธีการเรียนระดับผู้ปกครอง

ซึ่งโดยทั่วไปจะเป็นสัญลักษณ์ของความรู้ที่เหลือในชั้นเรียนมีเกี่ยวกับความสัมพันธ์ของคุณกับชั้นผู้ปกครองของคุณ


9

สมาชิกข้อมูลที่ได้รับความคุ้มครองสามารถเข้าถึงได้โดยคลาสใด ๆ ที่สืบทอดจากคลาสของคุณ อย่างไรก็ตามข้อมูลส่วนตัวสมาชิกไม่สามารถ สมมติว่าเรามีดังต่อไปนี้:

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

จากภายในส่วนขยายของคุณไปยังคลาสนี้การอ้างอิงthis.myPrivateMemberจะไม่ทำงาน อย่างไรก็ตามthis.myProtectedMemberจะ ค่านี้จะยังคงห่อหุ้มดังนั้นหากเรามีการเริ่มของชั้นนี้ที่เรียกว่าmyObjแล้วmyObj.myProtectedMemberจะไม่ทำงานจึงเป็นสิ่งที่คล้ายกันในการทำงานเพื่อเป็นสมาชิกข้อมูลส่วนตัว


8
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

จากตัวอย่างนี้สำหรับ java ... ฉันคิดว่าตารางเล็ก ๆ น่าจะคุ้มค่าพันคำ :)


Java มีเฉพาะการสืบทอดสาธารณะ
Zelldon

นี่ไม่ใช่หัวข้อที่จะพูดเกี่ยวกับ java แต่ไม่ผิดคุณทำตามลิงก์ในคำตอบของฉันด้านบนเพื่อดูรายละเอียด
Enissay

คุณพูดถึง java ดังนั้นจึงเป็นหัวข้อ และตัวอย่างของคุณจัดการตัวระบุที่ใช้ใน jaca คำถามเกี่ยวกับตัวระบุสำหรับการสืบทอดที่ไม่มีอยู่ใน Java ทำให้เกิดความแตกต่าง หากฟิลด์ในซูเปอร์คลาสเป็นสาธารณะและการสืบทอดเป็นส่วนตัวฟิลด์จะสามารถเข้าถึงได้เฉพาะภายในคลาสย่อยเท่านั้น ข้างนอกไม่มีสิ่งบ่งชี้ว่าคลาสย่อยขยายซูเปอร์คลาส แต่ตารางของคุณจะอธิบายเฉพาะตัวระบุสำหรับเขตข้อมูลและวิธีการ
Zelldon

7

สรุป:

  • ส่วนตัว: ไม่มีใครสามารถดูได้ยกเว้นในชั้นเรียน
  • ได้รับการป้องกัน: คลาสส่วนตัว + ที่ได้รับสามารถดูได้
  • สาธารณะ: โลกสามารถมองเห็นได้

เมื่อรับช่วงคุณสามารถ (ในบางภาษา) เปลี่ยนประเภทการป้องกันของข้อมูลสมาชิกในทิศทางที่แน่นอนเช่นจากการป้องกันสู่สาธารณะ


6

เอกชน:

สมาชิกส่วนตัวของคลาสฐานสามารถเข้าถึงได้โดยสมาชิกของคลาสฐานนั้นเท่านั้น

สาธารณะ:

สมาชิกสาธารณะของคลาสฐานสามารถเข้าถึงได้โดยสมาชิกของคลาสฐานนั้นสมาชิกของคลาสที่ได้รับรวมถึงสมาชิกที่อยู่นอกคลาสพื้นฐานและคลาสที่ได้รับ

มีการป้องกัน:

สมาชิกที่ได้รับความคุ้มครองของคลาสพื้นฐานสามารถเข้าถึงได้โดยสมาชิกของคลาสพื้นฐานเช่นเดียวกับสมาชิกของคลาสที่ได้รับ


ในระยะสั้น:

ส่วนตัว : ฐาน

ได้รับการป้องกัน : ฐาน + มา

สาธารณะ : ฐาน + มา + สมาชิกคนอื่น ๆ


5

ฉันพบคำตอบง่ายๆและคิดว่าจะโพสต์ไว้เพื่ออ้างอิงในอนาคตของฉันด้วย

มันมาจากลิงค์ http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

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
}

3

มันคือการป้องกันการเข้าถึงของสาธารณะและสมาชิกที่ได้รับการป้องกันของคลาสฐานในคลาสที่ได้รับ ด้วยการสืบทอดสาธารณะคลาสที่ได้รับสามารถเห็นสาธารณะและสมาชิกที่ได้รับการป้องกันของฐาน ด้วยการสืบทอดส่วนตัวไม่สามารถทำได้ ด้วยการป้องกันคลาสที่ได้รับและคลาสใด ๆ ที่ได้รับจากสิ่งนั้นสามารถมองเห็นได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.