ตัดสินจากถ้อยคำของคำถามของคุณ (คุณใช้คำว่า "ซ่อน") คุณรู้อยู่แล้วว่าเกิดอะไรขึ้นที่นี่ ปรากฏการณ์นี้เรียกว่า "การซ่อนชื่อ" ด้วยเหตุผลบางอย่างทุกครั้งที่มีคนถามคำถามว่าทำไมการซ่อนชื่อเกิดขึ้นผู้ที่ตอบว่าอาจเรียกว่า "การซ่อนชื่อ" และอธิบายวิธีการใช้งาน (ซึ่งคุณอาจรู้อยู่แล้ว) หรืออธิบายวิธีแทนที่มัน ไม่เคยถาม) แต่ดูเหมือนว่าไม่มีใครสนใจที่จะตอบคำถาม "ทำไม" จริง
การตัดสินใจเหตุผลเบื้องหลังการซ่อนชื่อนั่นคือเหตุผลว่าทำไมมันจึงถูกออกแบบมาในภาษา C ++ คือการหลีกเลี่ยงพฤติกรรมที่ไม่คาดคิดที่ไม่คาดคิดและอันตรายที่อาจเกิดขึ้นได้ โอเวอร์โหลดในคลาสที่กำหนด คุณอาจรู้ว่าในการแก้ปัญหาการโอเวอร์โหลด C ++ ทำงานได้โดยเลือกฟังก์ชั่นที่ดีที่สุดจากชุดของผู้สมัคร สิ่งนี้ทำได้โดยการจับคู่ประเภทของอาร์กิวเมนต์กับประเภทของพารามิเตอร์ กฎการจับคู่อาจมีความซับซ้อนในบางครั้งและมักนำไปสู่ผลลัพธ์ที่อาจถูกมองว่าไร้เหตุผลโดยผู้ใช้ที่ไม่ได้เตรียมตัวไว้ การเพิ่มฟังก์ชั่นใหม่ให้กับชุดของฟังก์ชั่นที่มีอยู่ก่อนหน้านี้อาจส่งผลให้เกิดการเปลี่ยนแปลงที่รุนแรงในผลลัพธ์ความละเอียดเกินพิกัด
ตัวอย่างเช่นสมมติว่าชั้นฐานB
มีฟังก์ชั่นสมาชิกfoo
ที่ใช้พารามิเตอร์ของประเภทvoid *
และทุกสายที่จะได้รับการแก้ไขไปfoo(NULL)
B::foo(void *)
สมมติว่าไม่มีที่หลบซ่อนชื่อและที่นี้ปรากฏอยู่ในชั้นเรียนที่แตกต่างกันลงมาจากB::foo(void *)
B
แต่ขอบอกว่าในบาง [อ้อมระยะไกล] ลูกหลานD
ของชั้นB
ฟังก์ชั่นfoo(int)
ที่มีการกำหนด ตอนนี้ไม่มีการซ่อนชื่อD
มีทั้งfoo(void *)
และfoo(int)
มองเห็นได้และมีส่วนร่วมในการแก้ปัญหาเกินพิกัด ฟังก์ชั่นใดจะเรียกการfoo(NULL)
แก้ไขถ้าทำผ่านวัตถุประเภทD
? พวกเขาจะแก้ปัญหาD::foo(int)
เนื่องจากint
เป็นการจับคู่ที่ดีกว่าสำหรับศูนย์รวม (เช่นNULL
) กว่าตัวชี้ประเภทใดก็ได้ ดังนั้นตลอดลำดับชั้นเรียกร้องให้foo(NULL)
แก้ปัญหาหนึ่งฟังก์ชั่นในขณะที่อยู่ในD
(และภายใต้) พวกเขาก็แก้ไขไปยังอีก
ตัวอย่างอื่นได้รับในการออกแบบและวิวัฒนาการของ C ++หน้า 77:
class Base {
int x;
public:
virtual void copy(Base* p) { x = p-> x; }
};
class Derived{
int xx;
public:
virtual void copy(Derived* p) { xx = p->xx; Base::copy(p); }
};
void f(Base a, Derived b)
{
a.copy(&b); // ok: copy Base part of b
b.copy(&a); // error: copy(Base*) is hidden by copy(Derived*)
}
หากไม่มีกฎนี้สถานะของ b จะถูกอัปเดตบางส่วนซึ่งนำไปสู่การแบ่งส่วน
พฤติกรรมนี้ถือว่าไม่พึงประสงค์เมื่อภาษาได้รับการออกแบบ วิธีการที่ดีกว่านั้นได้มีการตัดสินใจที่จะปฏิบัติตามข้อกำหนด "การซ่อนชื่อ" ซึ่งหมายความว่าแต่ละชั้นเรียนเริ่มต้นด้วย "แผ่นงาน" ที่เกี่ยวกับแต่ละชื่อวิธีที่ประกาศไว้ เพื่อแทนที่พฤติกรรมนี้จำเป็นต้องมีการดำเนินการที่ชัดเจนจากผู้ใช้: แต่เดิมเป็นการประกาศวิธีการสืบทอด (ปัจจุบันเลิกใช้แล้ว) ซึ่งตอนนี้เป็นการใช้การประกาศอย่างชัดเจน
ในขณะที่คุณสังเกตเห็นอย่างถูกต้องในโพสต์ต้นฉบับของคุณ (ฉันหมายถึงคำพูด "Not polymorphic") พฤติกรรมนี้อาจถูกมองว่าเป็นการละเมิดความสัมพันธ์ระหว่าง IS-A ระหว่างชั้นเรียน เรื่องนี้เป็นเรื่องจริง แต่เห็นได้ชัดว่าเมื่อก่อนตัดสินใจว่าการซ่อนชื่อท้ายจะพิสูจน์ได้ว่าเป็นความชั่วร้ายที่น้อยกว่า