ฉันได้รับคำตอบในรูปแบบของบทสนทนาเพื่อการอ่านที่ดีขึ้น:
ทำไมเราถึงต้องการฟังก์ชั่นเสมือนจริง?
เนื่องจากความแตกต่าง
ความแตกต่างคืออะไร?
ความจริงที่ว่าตัวชี้ฐานยังสามารถชี้ไปยังวัตถุชนิดที่ได้รับ
ความหมายของความหลากหลายนี้นำไปสู่ความต้องการฟังก์ชั่นเสมือนจริงอย่างไร?
ผ่านการผูกไว้ล่วงหน้า
การรวมก่อนหน้าคืออะไร
การรวมก่อนหน้า (การคอมไพล์เวลาคอมไพล์) ใน C ++ หมายความว่าการเรียกใช้ฟังก์ชันได้รับการแก้ไขก่อนที่จะเรียกใช้งานโปรแกรม
ดังนั้น...?
ดังนั้นหากคุณใช้ประเภทฐานเป็นพารามิเตอร์ของฟังก์ชั่นคอมไพเลอร์จะรับรู้เฉพาะอินเตอร์เฟสฐานและถ้าคุณเรียกใช้ฟังก์ชันนั้นด้วยข้อโต้แย้งใด ๆ จากคลาสที่ได้รับมันจะถูกตัดออกซึ่งไม่ใช่สิ่งที่คุณต้องการจะเกิดขึ้น
หากไม่ใช่สิ่งที่เราต้องการจะเกิดขึ้นทำไมจึงได้รับอนุญาต
เพราะเราต้องการความแตกต่าง!
แล้ว Polymorphism นั้นมีประโยชน์อย่างไร?
คุณสามารถใช้ตัวชี้ชนิดฐานเป็นพารามิเตอร์ของฟังก์ชันเดียวและในเวลาทำงานของโปรแกรมของคุณคุณสามารถเข้าถึงอินเทอร์เฟซชนิดที่ได้รับมา (เช่นฟังก์ชั่นสมาชิกของพวกเขา) โดยไม่มีปัญหาใด ๆ ตัวชี้ฐาน
ฉันยังไม่รู้ว่าฟังก์ชั่นเสมือนอะไรที่ดีสำหรับ ... ! และนี่เป็นคำถามแรกของฉัน!
นี่เป็นเพราะคุณถามคำถามของคุณเร็วเกินไป!
ทำไมเราถึงต้องการฟังก์ชั่นเสมือนจริง?
สมมติว่าคุณเรียกใช้ฟังก์ชันที่มีตัวชี้ฐานซึ่งมีที่อยู่ของวัตถุจากหนึ่งในคลาสที่ได้รับ ดังที่เราได้กล่าวถึงข้างต้นในช่วงรันไทม์ตัวชี้นี้ได้รับการพิจารณาจนดีอย่างไรก็ตามเราคาดว่าจะมีวิธีการ (== ฟังก์ชั่นสมาชิก) "จากคลาสที่ได้รับ" ของเราเพื่อดำเนินการ! อย่างไรก็ตามวิธีการเดียวกัน (หนึ่งที่มีส่วนหัวเดียวกัน) ได้ถูกกำหนดไว้แล้วในคลาสฐานดังนั้นทำไมโปรแกรมของคุณควรเลือกวิธีอื่น? ในคำอื่น ๆ ที่ฉันหมายถึงคุณจะบอกสถานการณ์นี้ได้อย่างไรจากสิ่งที่เราเคยเห็นเคยเกิดขึ้นมาก่อน
คำตอบสั้น ๆ คือ "ฟังก์ชั่นสมาชิกเสมือนในฐาน" และคำตอบอีกต่อไปก็คือ "ในขั้นตอนนี้ถ้าโปรแกรมเห็นฟังก์ชั่นเสมือนจริงในคลาสฐานจะรู้ (รู้ตัว) ว่าคุณกำลังพยายามใช้ polymorphism "และอื่น ๆ ไปที่คลาสที่ได้รับ (โดยใช้v-table , รูปแบบของการรวมภายหลัง) เพื่อค้นหาว่าวิธีอื่นที่มีส่วนหัวเดียวกัน
ทำไมการใช้งานที่แตกต่างกัน?
คุณสนับมือ! ไปอ่านหนังสือดี ๆ !
ตกลงรอสักครู่รอทำไมใครจะรำคาญที่จะใช้ตัวชี้ฐานเมื่อเขา / เธอสามารถใช้พอยน์เตอร์ที่ได้รับมาได้? คุณเป็นผู้ตัดสินปวดหัวทั้งหมดนี้คุ้มค่าหรือไม่ ดูตัวอย่างสองสิ่งนี้:
// 1:
Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();
// 2:
Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();
ตกลงแม้ว่าฉันคิดว่า1ยังดีกว่า2คุณสามารถเขียน1เช่นนี้:
// 1:
Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();
และยิ่งกว่านั้นคุณควรตระหนักว่านี่เป็นเพียงการใช้ทุกสิ่งที่ฉันได้อธิบายให้คุณทราบแล้ว แทนที่จะเป็นเช่นนี้ให้สมมติว่าสถานการณ์ที่คุณมีฟังก์ชั่นในโปรแกรมของคุณที่ใช้วิธีการจากแต่ละคลาสที่ได้รับตามลำดับ (getMonthBenefit ()):
double totalMonthBenefit = 0;
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
totalMonthBenefit += x -> getMonthBenefit();
}
ทีนี้ลองเขียนใหม่โดยไม่ปวดหัว!
double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();
และอันที่จริงนี่อาจเป็นตัวอย่างที่ถูกวางแผนไว้เช่นกัน!