สมาชิกส่วนบุคคลและที่ได้รับการป้องกัน: C ++


276

ใครสามารถสอนฉันถึงความแตกต่างระหว่างprivateและprotectedสมาชิกในชั้นเรียนได้หรือไม่

ผมเข้าใจจากการประชุมการปฏิบัติที่ดีที่สุดที่ตัวแปรและฟังก์ชั่นที่ไม่ได้เรียกว่านอกชั้นเรียนควรจะทำprivate- แต่ฉันกำลังมองหาที่MFCโครงการMFCprotectedดูเหมือนว่าจะโปรดปราน

อะไรคือความแตกต่างและสิ่งที่ฉันควรใช้

คำตอบ:


374

สมาชิกส่วนตัวสามารถเข้าถึงได้เฉพาะในชั้นเรียนที่กำหนดไว้

สมาชิกที่ได้รับความคุ้มครองสามารถเข้าถึงได้ในชั้นเรียนที่กำหนดพวกเขาและในชั้นเรียนที่สืบทอดมาจากชั้นเรียนนั้น

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

แก้ไข 2: ใช้สิ่งที่สมเหตุสมผลในบริบทของปัญหาของคุณ คุณควรพยายามทำให้สมาชิกเป็นส่วนตัวทุกครั้งที่ทำได้เพื่อลดการแต่งงานและป้องกันการใช้คลาสพื้นฐาน แต่ถ้าไม่สามารถทำได้ให้ใช้สมาชิกที่ได้รับความคุ้มครอง ตรวจสอบคำถามที่พบบ่อย C ++เพื่อความเข้าใจที่ดีขึ้นของปัญหา คำถามเกี่ยวกับตัวแปรที่ได้รับการป้องกันอาจช่วยได้เช่นกัน


12
ลิงก์ไปยัง C ++ FAQ Lite ได้ย้ายไปที่isocpp.org/wiki/faq/basics-of-inheritance
avner

134

สมาชิกสาธารณะของคลาส A สามารถเข้าถึงได้สำหรับทุกคนและทุกคน

สมาชิกที่ได้รับการป้องกันของคลาส A จะไม่สามารถเข้าถึงได้นอกรหัส A แต่สามารถเข้าถึงได้จากรหัสของคลาสใด ๆ ที่ได้รับจาก A

สมาชิกส่วนตัวของคลาส A ไม่สามารถเข้าถึงได้นอกรหัส A หรือจากรหัสของคลาสใด ๆ ที่ได้มาจาก A

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

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


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

@CashCow the protected data of the base class is part of the data of the derived class.แน่นอน ถ้าอย่างนั้นจะดีกว่าไหมถ้าให้ผู้เขียนของคลาสที่ได้รับมาประกาศว่าข้อมูลในชั้นเรียนของพวกเขาแทนที่จะเป็นของฉัน ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug.ในรูปแบบ NVI เป้าหมายคือเพื่อทำให้ทุกอย่างเป็นส่วนตัวรวมถึง วิธีการเพื่อจำกัดความเสียหายที่ผู้เขียนคลาสที่ได้รับสามารถทำได้กับลำดับชั้น วิธีการป้องกันเป็นปัญหาที่อาจเกิดขึ้นอยู่แล้ว ฉันไม่มั่นใจว่าการทำให้รุนแรงขึ้นด้วยการใช้สถานะที่ได้รับการป้องกันเป็นวิธีการที่เหมาะสม
paercebal

อาจเป็นได้ซึ่งคุณจะต้องมี "getters" เสมือนในคลาสฐานเพื่อเข้าถึง และในขณะที่คุณสามารถมีคลาสในระหว่างทำวิธีต่าง ๆ รูปแบบข้อมูลสามารถนำมาใช้มันไม่จริงเสมอไปทำเช่นนั้น ตัวอย่างเช่น "รูปแบบ" ซึ่งพบได้ทั่วไปในภาษาที่ไม่มีตัวแก้ไข "const" แม้ว่าไม่จำเป็นต้องใช้เวลาส่วนใหญ่ใน C ++ คือการมีคลาสพื้นฐานแบบอ่านอย่างเดียวและคลาสที่เขียนได้ ใน C ++ สิ่งนี้สามารถทำได้อย่างง่ายดายเพราะคุณต้องการโหลดมากกว่าหนึ่งวิธี (เริ่มต้น) ข้อมูล
CashCow

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

63

สมาชิกที่ได้รับความคุ้มครองสามารถเข้าถึงได้จากคลาสที่ได้รับ บุคคลไม่สามารถทำได้

class Base {

private: 
  int MyPrivateInt;
protected: 
  int MyProtectedInt;
public:
  int MyPublicInt;
};

class Derived : Base
{
public:
  int foo1()  { return MyPrivateInt;} // Won't compile!
  int foo2()  { return MyProtectedInt;} // OK  
  int foo3()  { return MyPublicInt;} // OK
};‌‌

class Unrelated 
{
private:
  Base B;
public:
  int foo1()  { return B.MyPrivateInt;} // Won't compile!
  int foo2()  { return B.MyProtectedInt;} // Won't compile
  int foo3()  { return B.MyPublicInt;} // OK
};

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


3
ฉันขอแตกต่างกัน: หากมีความเป็นไปได้ที่จาง ๆ ที่ไม่มีคลาสย่อยที่จะต้องการให้เป็นแบบส่วนตัว ถ้าคุณไม่ต้องการให้คลาสย่อยของคุณใช้รูปแบบวิธีการของเทมเพลต
xtofl

23

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


9

ทุกอย่างขึ้นอยู่กับสิ่งที่คุณต้องการทำและสิ่งที่คุณต้องการให้คลาสที่ได้รับสามารถมองเห็นได้

class A
{
private:
    int _privInt = 0;
    int privFunc(){return 0;}
    virtual int privVirtFunc(){return 0;}
protected:
    int _protInt = 0;
    int protFunc(){return 0;}
public:
    int _publInt = 0;
    int publFunc()
    {
         return privVirtFunc();
    }
};

class B : public A
{
private:
    virtual int privVirtFunc(){return 1;}
public:
    void func()
    {
        _privInt = 1; // wont work
        _protInt = 1; // will work
        _publInt = 1; // will work
        privFunc(); // wont work
        privVirtFunc(); // wont work
        protFunc(); // will work
        publFunc(); // will return 1 since it's overridden in this class
    }
}

6

คุณสมบัติและวิธีการทำเครื่องหมายว่าprotectedเป็น - ไม่เหมือนของส่วนตัว - ยังคงมองเห็นได้ในคลาสย่อย

privateถ้าคุณไม่ต้องการที่จะใช้หรือให้ความเป็นไปได้ที่จะแทนที่วิธีการในการย่อยเป็นไปได้ผมอยากทำให้พวกเขา


2
คลาสที่ได้รับสามารถแทนที่ฟังก์ชั่นเสมือนส่วนตัวของฐานได้
James Hopkin

6

โปรดดูที่คำถามตัวแปรสมาชิกที่ได้รับการป้องกัน ขอแนะนำให้ใช้ส่วนตัวเป็นค่าเริ่มต้น (เช่นเดียวกับ C ++ classses do) เพื่อลดการแต่งงานกัน ตัวแปรสมาชิกที่ได้รับความคุ้มครองมักเป็นความคิดที่ไม่ดีส่วนฟังก์ชั่นสมาชิกที่ได้รับการป้องกันสามารถนำมาใช้ได้เช่นรูปแบบวิธีการของแม่แบบ


ขำ ๆ ฉันแก้ไขมันในโพสต์ก่อนที่ฉันจะเห็นคุณ upvoted เพราะนกสะดุดขนบนการเชื่อมโยงเดียวกัน :)
Firas Assaad

4

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

แน่นอนว่าฟังก์ชั่นของเพื่อนทำให้สิ่งนี้ออกไปนอกหน้าต่าง แต่ก็ไม่เป็นไร


4

สมาชิกส่วนตัวสามารถเข้าถึงได้จากภายในชั้นเรียนเท่านั้นสมาชิกที่ได้รับความคุ้มครองสามารถเข้าถึงได้ในชั้นเรียนและชั้นเรียนที่ได้รับ มันเป็นคุณสมบัติของการสืบทอดในภาษา OO

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


3

ส่วนตัว = เข้าถึงได้โดยมารดา (ระดับฐาน) เท่านั้น (เช่นผู้ปกครองเท่านั้นที่สามารถเข้าห้องนอนของผู้ปกครองของฉัน)

ได้รับการป้องกัน = เข้าถึงได้โดยมารดา (ระดับฐาน) และลูกสาวของเธอ (เช่นมีเพียงพ่อแม่เท่านั้นที่สามารถเข้าไปในห้องนอนของพ่อแม่ของฉันได้ แต่ได้รับอนุญาตจากลูกชาย / ลูกสาวให้เดินเข้าไปในห้องนอนของผู้ปกครอง)

สาธารณะ = เข้าถึงได้โดยมารดา (ระดับฐาน), ลูกสาวและทุกคน (เช่นมีเพียงพ่อแม่เท่านั้นที่สามารถเข้าไปในห้องนอนของพ่อแม่ได้ แต่เป็นปาร์ตี้ในบ้าน - mi casa su casa)


2

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


คุณสามารถใช้ฟังก์ชั่นอินไลน์ที่นำมาใช้ในการประกาศคลาส คอมไพเลอร์จะปรับให้เหมาะที่สุดออกไป (และนั่นจะเป็นวิธีที่ดีในการบังคับใช้การเข้าถึงแบบอ่านอย่างเดียวกับตัวแปรสมาชิกส่วนตัวเช่น)
พอลแซนเดอร์ส

2

privateเป็นที่ต้องการสำหรับข้อมูลสมาชิก สมาชิกในคลาส C ++ เป็นprivateค่าเริ่มต้น

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

privateไม่สามารถเข้าถึงได้เลย ไม่มีใครสามารถใช้พวกเขานอกห้องเรียนและไม่มีใครสามารถใช้ผิดวัตถุประสงค์ ไม่แม้แต่ในชั้นเรียนที่ได้รับ

protectedประนีประนอมเพราะมันสามารถใช้ในชั้นเรียนที่ได้รับ เมื่อคุณได้รับจากชั้นเรียนคุณมีความเข้าใจที่ดีเกี่ยวกับชั้นฐานและคุณระมัดระวังที่จะไม่ใช้สมาชิกเหล่านี้ในทางที่ผิด

เอ็มเอฟเป็น c ++ เสื้อคลุมสำหรับ Windows API ก็ชอบและpublic protectedชั้นเรียนที่สร้างโดย Visual Studio ตัวช่วยสร้างการมีการผสมผสานที่น่าเกลียดของprotected, publicและprivateสมาชิก แต่มีตรรกะบางอย่างในคลาส MFC เอง

สมาชิกเช่นSetWindowTextนี้เป็นpublicเพราะคุณมักจะต้องเข้าถึงสมาชิกเหล่านี้

สมาชิกเช่นOnLButtonDownจัดการการแจ้งเตือนที่ได้รับจากหน้าต่าง protectedพวกเขาไม่ควรจะเข้าถึงได้ดังนั้นพวกเขาจะ คุณยังสามารถเข้าถึงได้ในคลาสที่ได้รับเพื่อแทนที่ฟังก์ชันเหล่านี้

สมาชิกบางคนต้องทำเธรดและลูปข้อความพวกเขาไม่ควรเข้าถึงหรือลบล้างดังนั้นพวกเขาจึงประกาศว่าเป็น private

ในโครงสร้าง C ++ สมาชิกจะเป็นpublicค่าเริ่มต้น โครงสร้างมักใช้สำหรับข้อมูลเท่านั้นไม่ใช่วิธีการดังนั้นpublicการประกาศจึงถือว่าปลอดภัย


1
คุณเขียน "สมาชิกในคลาส C ++ ได้รับการป้องกันโดยค่าเริ่มต้น" ตามมาตรฐานพวกเขาเป็นส่วนตัวหรือสาธารณะตามค่าเริ่มต้นขึ้นอยู่กับคำหลักที่ใช้ในการกำหนด (14p3) Microsoft เบี่ยงเบนจากมาตรฐานที่นี่หรือไม่
Alexander Klauer

@AlexanderKlauer ฉันผิดมันเป็นprivateค่าเริ่มต้นใน Visual Studio มันเป็นprivateค่าเริ่มต้นใน gcc เช่นกันมันไม่เคยเป็นpublicค่าเริ่มต้น เว้นแต่ฉันผิดอีกครั้ง ฉันไม่พบมาตรฐานที่คุณอ้างถึง
Barmak Shemirani

ขออภัยฉันควรเจาะจงมากขึ้น ฉันอ้างถึงมาตรฐาน C ++ 17 มาตรฐาน C ++ 11 มีข้อความเดียวกันใน 11p3 คุณสามารถปรับปรุงคำตอบของคุณ? ขอบคุณ!
Alexander Klauer

1

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


1
  • ส่วนตัว : มันเป็นตัวระบุการเข้าถึง โดยค่าเริ่มต้นตัวแปรอินสแตนซ์ (สมาชิก) หรือวิธีการของคลาสใน c ++ / java เป็นส่วนตัว ในระหว่างการสืบทอดรหัสและข้อมูลจะได้รับการสืบทอดอยู่เสมอ แต่ไม่สามารถเข้าถึงได้นอกชั้นเรียน เราสามารถประกาศสมาชิกข้อมูลของเราเป็นส่วนตัวเพื่อให้ไม่มีใครสามารถเปลี่ยนแปลงตัวแปรสมาชิกของเราได้โดยตรงและเราสามารถจัดหาผู้ให้บริการสาธารณะและผู้ตั้งค่าเพื่อเปลี่ยนสมาชิกส่วนตัวของเรา และแนวคิดนี้ถูกนำไปใช้เสมอในกฎเกณฑ์ทางธุรกิจ

  • ได้รับการป้องกัน : นอกจากนี้ยังเป็นตัวระบุการเข้าถึง ใน C ++ สมาชิกที่ได้รับการป้องกันสามารถเข้าถึงได้ภายในคลาสและคลาสที่สืบทอด แต่ไม่ได้อยู่นอกคลาส ใน Java สมาชิกที่ได้รับการป้องกันจะสามารถเข้าถึงได้ภายในคลาสไปยังคลาสที่สืบทอดมารวมถึงคลาสทั้งหมดที่อยู่ในแพ็คเกจเดียวกัน


0

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

  • ตัวชี้ไปยังคลาสที่ได้รับโดยตรงหรือโดยอ้อม
  • การอ้างอิงไปยังคลาสที่ได้รับโดยตรงหรือโดยอ้อม
  • วัตถุของคลาสที่ได้รับโดยตรงหรือโดยอ้อม

0

ส่วนตัว:สามารถเข้าถึงได้โดยฟังก์ชั่นสมาชิกชั้นเรียนและฟังก์ชั่นเพื่อนหรือชั้นเรียนเพื่อน สำหรับคลาส C ++ นี่คือตัวระบุการเข้าถึงเริ่มต้น

ป้องกัน:เข้าถึงได้โดยฟังก์ชั่นสมาชิกคลาส, ฟังก์ชั่นเพื่อนหรือคลาสเพื่อน & คลาสที่ได้รับ

  • คุณสามารถรักษาตัวแปรสมาชิกหรือฟังก์ชั่นของสมาชิก (แม้พิมพ์หรือชั้นใน) เป็นส่วนตัวหรือได้รับการคุ้มครองตามความต้องการของคุณ
  • ส่วนใหญ่เวลาที่คุณให้สมาชิกคลาสเป็นส่วนตัวและเพิ่มฟังก์ชั่นรับ / ตั้งค่าเพื่อแค็ปซูล ซึ่งจะช่วยในการบำรุงรักษารหัส
  • โดยทั่วไปฟังก์ชั่นส่วนตัวจะใช้เมื่อคุณต้องการให้ฟังก์ชั่นสาธารณะของคุณเป็นแบบแยกส่วนหรือเพื่อกำจัดรหัสซ้ำ ๆ แทนที่จะเขียนโค้ดทั้งหมดลงในฟังก์ชั่นเดียว ซึ่งจะช่วยในการบำรุงรักษารหัส

อ้างอิงลิงค์นี้เพื่อดูรายละเอียดเพิ่มเติม


-2

ตัวดัดแปลงการเข้าถึงส่วนตัวและที่ได้รับการป้องกันเป็นสิ่งเดียวและเดียวเท่านั้นที่สมาชิกที่ได้รับการป้องกันของคลาสพื้นฐานสามารถเข้าถึงได้นอกขอบเขตของคลาสพื้นฐานในคลาสย่อย (ที่ได้รับ) นอกจากนี้ยังใช้กับมรดก แต่ด้วยโมดิฟายเออร์ส่วนตัวสมาชิกของคลาสฐานสามารถเข้าถึงได้ในขอบเขตหรือรหัสของคลาสพื้นฐานและฟังก์ชันเพื่อนเท่านั้น '' ''


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