คำนำ
ชื่อ "ปัญหาของการลดการเข้าถึงคลาสย่อยผ่านฟังก์ชั่นคลาสแม่ใน Java และ C ++" ดูเหมือนจะเป็นวิชาการมากกว่า แต่มันเป็นปัญหาที่ง่ายต่อการเพิกเฉย บทความนี้มุ่งมั่นที่จะอธิบายรายละเอียดเกี่ยวกับความแตกต่างระหว่างปัญหานี้ใน Java และ C ++
ก่อนอื่นเราจะแนะนำสิ่งที่ "การลดการเข้าถึงของคลาสย่อยของการเข้าถึงฟังก์ชั่นระดับพาเรนต์" สำหรับการสืบทอดคลาสย่อยสามารถแทนที่ "ฟังก์ชั่นเสมือนจริง" ของคลาสแม่ - แม้ว่าจะไม่มีฟังก์ชั่นเสมือนจริงใน Java ฟังก์ชั่น Java ทั้งหมดถือได้ว่าเป็นฟังก์ชั่นเสมือนจริงเพราะฟังก์ชั่น Java ทั้งหมดสามารถแทนที่ด้วย subclasses ที่นี่เรายืมความหมายของคำว่า "ฟังก์ชั่นเสมือนจริง" เท่านั้นและอย่าขุดลงในรายละเอียดของภาษา ทั้ง Java และ C ++ อนุญาตให้เปลี่ยนการเข้าถึงฟังก์ชั่นเมื่อเอาชนะ สิ่งที่เรียกว่า "การเข้าถึง" คือการใช้อักขระควบคุมการเข้าถึงเช่นสาธารณะการป้องกันและส่วนตัวเพื่อแก้ไขเพื่อควบคุมว่าสามารถเข้าถึงฟังก์ชั่นได้หรือไม่ โดยปกติแล้วลำดับการเข้าถึงคือ (เนื่องจากไม่มีแนวคิดของแพ็คเกจใน C ++ การควบคุมการเข้าถึงแพ็คเกจไม่ได้รับการพิจารณาในขณะนี้ซึ่งไม่ส่งผลกระทบต่อการสนทนาที่นี่):
สาธารณะ> ได้รับการคุ้มครอง> ส่วนตัว
ใช้ Java เป็นตัวอย่าง:
ฐานชั้นเรียน {void ที่ได้รับการป้องกัน sayshello () {system.out.println ("สวัสดีในฐาน"); }} เด็กชั้นเรียนขยายฐาน {โมฆะสาธารณะ sayshello () {system.out.println ("สวัสดีในเด็ก"); - หมายเหตุ: ฟังก์ชั่น sayHello() ที่นี่ ในฐานคลาสแม่ฟังก์ชั่นนี้ได้รับการแก้ไขโดยใช้อักขระควบคุมการเข้าถึงที่ได้รับการป้องกัน และคลาสย่อยใช้สาธารณะแทนจะไม่มีปัญหา เมื่อคลาสย่อยแทนที่ฟังก์ชั่นคลาสแม่การขยายการเข้าถึงมักจะไม่เป็นปัญหา
Java และ C ++ ใช้กลยุทธ์ที่แตกต่างกันเมื่อคลาสย่อยลดการเข้าถึงการเข้าถึงฟังก์ชั่นคลาสแม่
ก่อนอื่นให้ใช้ Java เป็นตัวอย่างและดูรหัสต่อไปนี้:
ฐานชั้นเรียน {โมฆะสาธารณะ sayshello () {system.out.println ("สวัสดีในฐาน"); }} ชั้นเด็กขยายฐาน {โมฆะส่วนตัว sayshello () {system.out.println ("สวัสดีในเด็ก"); -ในรหัสข้างต้นจะมีข้อผิดพลาดในการรวบรวมในบรรทัดที่ไฮไลต์ 8 - รหัสนี้ไม่สามารถรวบรวมได้เลย! Java ไม่อนุญาตให้คลาสย่อยเพื่อลดการเข้าถึงเมื่อเขียนทับฟังก์ชั่นคลาสแม่ สำหรับเหตุผลเราสามารถใช้ตัวอย่างเพื่อแสดง ตัวอย่างเช่นเราเขียนรหัสต่อไปนี้นอกชั้นเรียน:
ฐานฐาน = ฐานใหม่ (); base.sayhello (); base = เด็กใหม่ (); base.sayhello ();
หากสามารถรวบรวมรหัสก่อนหน้าได้มีความเป็นไปได้ที่เมื่อพื้นฐานชี้ไปที่ฐานใหม่ () สามารถเข้าถึง sayhello () ได้ แต่เมื่อฐานชี้ไปที่เด็กใหม่ (), sayhello () ไม่สามารถเข้าถึงได้! ในมุมมองของ Java นี่เป็นความขัดแย้งและควรหลีกเลี่ยงปัญหานี้ ดังนั้น Java จึงกำหนดจากมุมมองของคอมไพเลอร์ว่าเราไม่สามารถเขียนรหัสข้างต้นได้
สำหรับ C ++ สถานการณ์แตกต่างกัน มาดูตัวอย่าง C ++:
ฐานชั้นเรียน {สาธารณะ: Virtual Void Sayshello () {std :: cout << "Hello in Base"; }} ชั้นเรียนเด็ก: ฐานสาธารณะ {ส่วนตัว: โมฆะ sayshello () {std :: cout << "สวัสดีในเด็ก"; -รหัสนี้ถูกต้องอย่างสมบูรณ์ใน C ++ โปรดทราบว่า subclass ที่นี่จะลดการเข้าถึงเมื่อเขียนทับฟังก์ชั่นคลาสแม่ หากคุณไม่เห็นปัญหาใด ๆ เราสามารถเขียนรหัสต่อไปนี้นอกชั้นเรียน:
เด็กเด็ก; sayhello (); // ไม่สามารถรวบรวมได้เพราะ sayshello () เป็น static_cast <base &> (เด็ก) .sayhello (); // ไม่สามารถรวบรวมได้เพราะ Sayshello () เป็นสาธารณะ
การโทรบรรทัดที่ 2 ล้มเหลวเพราะในเด็ก sayHello() เป็นส่วนตัวและไม่สามารถเรียกได้จากภายนอก อย่างไรก็ตามเมื่อเราส่งเด็กไปยังวัตถุพื้นฐานโดยใช้ Static_cast สิ่งต่าง ๆ เปลี่ยนไป - สำหรับฐาน sayHello() เป็นสาธารณะดังนั้นจึงสามารถเรียกได้ตามปกติ
ด้วยเหตุนี้ตัวอย่างต่อไปนี้สามารถพบได้ในส่วนการเข้าถึงฟังก์ชั่นเสมือนจริงของบทควบคุมการเข้าถึงสมาชิกมาตรฐาน C ++ บทที่:
คลาส B {สาธารณะ: เสมือน int f ();}; คลาส D: สาธารณะ b {ส่วนตัว: int f ();}; void f () {d d; b* pb = & d; d* pd = & d; pb-> f (); // ตกลง: b :: f () เป็นสาธารณะ d :: f () ถูกเรียกใช้ pd-> f (); // ข้อผิดพลาด: d :: f () เป็นส่วนตัว}ในเรื่องนี้มาตรฐาน C ++ ให้คำอธิบาย:
การเข้าถึงถูกตรวจสอบที่จุดเรียกโดยใช้ประเภทของนิพจน์ที่ใช้เพื่อแสดงวัตถุที่เรียกใช้ฟังก์ชันสมาชิก (b* ในตัวอย่างด้านบน) การเข้าถึงฟังก์ชั่นสมาชิกในชั้นเรียนที่กำหนดไว้ (d ในตัวอย่างด้านบน) โดยทั่วไปไม่ทราบ
มีสองประเด็นสำคัญสำหรับการแปลอย่างง่าย:
ด้วยเหตุนี้ผู้โทร C ++ ดูเหมือนจะสามารถ "ฉลาด" ฟังก์ชั่นการโทรที่ไม่สามารถเข้าถึงได้ในตอนแรกผ่านการเปลี่ยนแปลงที่มีทักษะ ตัวอย่างที่ใช้งานได้จริงคือ: ใน QT ฟังก์ชั่น QObject::event() เป็นสาธารณะและ event() ฟังก์ชั่นถูกเปลี่ยนเป็นการป้องกัน สำหรับรายละเอียดคุณสามารถอ่านรหัสที่เกี่ยวข้องของ QT
โดยสรุปเมื่อ subclasses แทนที่ฟังก์ชั่นพาเรนต์ Java จำกัด อย่างเคร่งครัดว่า subclasses ไม่สามารถ จำกัด การเข้าถึงฟังก์ชั่นให้แคบลง แต่ C ++ ไม่มีข้อ จำกัด นี้ โดยส่วนตัวแล้วฉันเชื่อว่าจากมุมมองของวิศวกรรมซอฟต์แวร์กฎระเบียบของ Java มีความสำคัญทางวิศวกรรมมากขึ้นอย่างไม่ต้องสงสัยและการเรียกใช้ฟังก์ชั่นนั้นสอดคล้องกันมากขึ้น มาตรฐาน C ++ จะทำให้การใช้งานคอมไพเลอร์ง่ายขึ้นอย่างมาก แต่ไม่ใช่การอ้างอิงที่ดีสำหรับวิศวกรรม
PS: เวอร์ชันอย่างเป็นทางการของมาตรฐาน C ++ ต้องการการซื้อ แต่สามารถดาวน์โหลดร่างได้ฟรี ที่อยู่ดาวน์โหลดของร่างมาตรฐาน C ++ สามารถพบได้ในหน้าต่อไปนี้: https://isocpp.org/std/the-standard
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com