‫ในการบรรยายนี้ เราจะพูดถึงวิธีการเสมือนใน C++
‫เราเคยเห็นมันมาก่อน เราเคยใช้มัน แต่เราเข้าใจมันอย่างถ่องแท้หรือเปล่า?
‫มาดูกัน.
‫แนวคิดของเมธอดเสมือนคือช่วยให้เราสามารถแทนที่ฟังก์ชันในคลาสฐานได้
‫เราได้เห็นสิ่งนี้กับสิ่งต่าง ๆ เช่น เริ่มต้น เล่น และ Tic ใน Unreal แต่มาเจาะลึกเรื่องนี้กันดีกว่า และทำความเข้าใจว่าทำไมพวกเขาถึงถูกทำเครื่องหมายเป็นเสมือน
‫มันช่วยให้เราเปลี่ยนฟังก์ชันการทำงานในคลาสพื้นฐานนั้นได้ และมันทำบางสิ่งที่เรียกว่า Dynamic Dispatch ซึ่งเราจะพูดถึงในอีกสักครู่เพื่อให้เข้าใจว่าสิ่งนี้หมายถึงอะไรจริงๆ
‫และทำไมเมธอดเสมือนไม่ใช่ฟังก์ชันเริ่มต้นใน C++ เนื่องจากเป็นภาษาอื่นๆ มากมาย เช่น
‫C Sharp
‫ลองมาดูที่นี้
‫ฉันจะทำสิ่งนี้ในเว็บไซต์ CPP dot S-H เพื่อที่เราจะได้ไม่อยู่ใน Unreal ที่นี่เลย
‫เรากำลังมองหาฟังก์ชันดิบ C++ เพื่อให้คุณเข้าใจคุณลักษณะภาษานี้และวิธีการทำงาน
‫ตอนนี้ อย่างแรกที่ฉันจะทำคือ ไปข้างหน้าและล้างวิธีการหลัก
‫และในกรณีการใช้งานของเรา เราจะคิดถึงคลาสสำหรับปืน เนื่องจากนี่เป็นกรณีการใช้งานทั่วไปสำหรับเกม
‫มาดูคลาสที่เรียกมันว่า gun กันอย่างตรงไปตรงมา แล้วเราจะให้เนื้อหาของคลาสนี้เป็นแบบสาธารณะและเป็นวิธีการยิงแบบเป็นโมฆะ
‫และฉันจะดำเนินการต่อและประกาศเนื้อหาของวิธีการถ่ายภาพนี้ตรงนี้เพื่อให้ทุกอย่างเรียบง่ายมาก
‫อีกอย่าง คุณสามารถทำสิ่งนี้ได้ หากคุณไม่เคยเห็นสิ่งนี้มาก่อน แต่โดยทั่วไปแล้ว เราต้องการทำสิ่งต่าง
‫ๆ ในไฟล์ C++ แยกต่างหากเพื่อแยกสิ่งต่าง ๆ ออกจากกัน เพื่อให้เวลาในการรวบรวมเร็วขึ้นเป็นต้น
‫แต่ในที่นี้เป็นเพียงตัวอย่างของเล่น ไม่เป็นไร เราจะทำ STD C ออกมา
‫ดังนั้นการใช้ C ++ เป็นสตริงเอาต์พุตและเราจะเริ่มต้นเมื่อเราเรียกวิธีนี้แล้วเราจะสิ้นสุดบรรทัด
‫และนั่นคือร่างกายของวิธีการถ่ายภาพของเรา
‫และเราสามารถปิดท้ายชั้นเรียนด้วยเครื่องหมายปีกกาและอัฒภาค
‫มาใช้คลาสนี้กันต่อเถอะ
‫ฉันจะสร้างตัวแปรปืนของฉันใน main และฉันจะเรียก gun dot shoot ของฉันและมาดูกันว่าทุกอย่างทำงานที่นี่ตามที่ควรจะเป็นหรือไม่
‫กดปุ่มวิ่งแล้วปัง
‫กำลังเรียกวิธีการตามที่เราคาดหวัง
‫จะเกิดอะไรขึ้นถ้าฉันต้องการขยายปืนและบางทีอาจทำปืนไรเฟิลหรือปืนพก?
‫เรียกมันว่าปืนพก
‫ดังนั้นปืนพกระดับคลาสจึงเป็นมรดกจากปืนซึ่งจะทำอย่างนี้
‫และถ้าคุณไม่เคยเห็นสิ่งนี้มาก่อนเพราะคุณอาจไม่เคยเขียนสิ่งนี้มาก่อน
‫คุณจะต้องทำมรดกสาธารณะจากปืนเพื่อให้คลาสอื่นเห็นว่าคุณได้รับมรดกจากปืน
‫จากนั้นเราก็ทำในส่วนสาธารณะ เราอาจต้องการสร้างวิธีการยิงของเราเองสำหรับปืนพกที่จะมาแทนที่ฟังก์ชันนี้
‫และแทนที่จะพิมพ์ปังในตอนท้าย เราต้องการพิมพ์เม็ดยาเพราะเป็นปืนที่เล็กกว่า มันให้เสียงที่เล็กกว่า
‫และนั่นคือวิธีการยิงของเราที่นั่น
‫และขอปิดชั้นเรียนที่นั่น
‫และสิ่งที่เราอยากทำคือสร้างปืนพกให้ตัวเอง
‫ดังนั้นปืนพกปืนพกของฉันในวิธีหลักที่นี่
‫และเนื่องจากสิ่งเหล่านี้มีอยู่แล้วในวิธีหลัก เราจึงไม่ได้ใช้พอยน์เตอร์
‫นั่นเป็นเหตุผลที่เราใช้ตัวดำเนินการยิงที่นี่แทนลูกศร
‫ดังนั้นปืนพกของฉันจึงไม่ยิง
‫มาดูกันว่ามันทำอะไรได้บ้าง
‫ฉันคาดหวังว่ามันจะพิมพ์ PPU ซึ่งมันทำ
‫เย็น.
‫เอาล่ะ เรามาลบวิธีการของเราที่กำลังเรียกกัน
‫ยิงไปที่สิ่งเหล่านี้โดยตรงและมาดูกันว่าสิ่งต่าง ๆ จะเป็นอย่างไรด้วยตัวชี้
‫ฉันจะสร้างตัวชี้ปืนที่เรียกว่าปืน
‫ปีเตอร์.
‫และในบรรทัดถัดไป ผมสามารถทำได้ในบรรทัดเดียวกัน
‫แต่เพื่อความเรียบง่าย ฉันจะทำในบรรทัดถัดไป
‫ฉันจะตั้งค่าตัวชี้ปืนให้ชี้ไปที่ที่อยู่นั่นคือที่อยู่ของผู้ปฏิบัติงาน
‫ที่อยู่ของตัวแปรปืนของฉัน
‫และเนื่องจากนี่คือตัวชี้ เราจึงต้องใช้ตัวดำเนินการลูกศรเพื่อเรียกวิธีการยิง
‫ดังนั้นฉันจะเรียกปืนของฉันมาคลิกวิ่งและเราก็ได้รับผลที่นั่น
‫เย็น.
‫จะเกิดอะไรขึ้นถ้าฉันทำสิ่งเดียวกัน
‫แต่แทนที่จะตั้งค่าตัวชี้ปืนให้ชี้ไปที่ปืนของฉัน ฉันตั้งค่าให้ชี้ไปที่ปืนพกของฉัน
‫ไปข้างหน้าและวิ่งในขณะนี้
‫ตกลง.
‫นั่นเป็นพฤติกรรมที่น่าสนใจที่นั่น
‫สิ่งที่เกิดขึ้นที่นี่คือการเรียกวิธีการแรกนี้ในทั้งสองกรณี
‫เหตุใดจึงไม่เรียกวิธีการยิงครั้งที่สองนี้
‫เรามีปืนพกที่นี่เป็นตัวชี้
‫จะเกิดอะไรขึ้นหากคุณไม่มีเมธอดเสมือน โดยค่าเริ่มต้น C++ จะใช้ประเภทของพอยน์เตอร์ของคุณ
‫ซึ่งเป็นตัวชี้ปืน
‫จำไว้ว่ามันจะใช้ประเภทนั้นเพื่อค้นหาวิธีการโทร
‫ดังนั้นมันจะไปและเรียกวิธีการยิงนี้ที่ด้านบนมากกว่าวิธีการแทนที่ในปืนพก
‫เพื่อที่จะเรียกการแทนที่และวิธีการในปืนพก มันจะต้องเรียกว่ามันจะต้องมีตัวชี้แบบปืนพก
‫ตอนนี้ก็ดีแล้ว
‫และคุณจะเห็นว่าทำไมพวกเขาถึงทำเช่นนี้
‫เพื่อประสิทธิภาพ
‫C ++ นั้นเกี่ยวกับประสิทธิภาพ
‫หากมีบางสิ่งที่จะเสียค่าใช้จ่ายมากขึ้นเมื่อคอมไพล์ เมื่อมันรัน C++ จะไม่ทำโดยค่าเริ่มต้น เว้นแต่คุณจะขอให้ทำ
‫ดังนั้นมันจึงง่ายมากสำหรับ C++ ในการค้นหาและใช้งาน นี่คือตัวชี้ปืน ฉันจะเรียกวิธีนี้ว่าปืนชี้
‫และนี่คือที่มาของ Dynamic Dispatch
‫คำศัพท์แฟนซีนี้โดยพื้นฐานแล้วหมายความว่าเราไม่ต้องการให้ทำเช่นนั้น
‫สิ่งที่เราต้องการให้ทำคือพูดว่า เดี๋ยวก่อน อะไรกันแน่ที่เก็บไว้ในตัวชี้ปืนนั้น
‫ของจริงมีแบบไหนบ้าง?
‫และประเภทที่แท้จริงที่เรารู้ก็คือมันเป็นปืนพกแบบ
‫ดังนั้นเราจึงต้องถามตัวเองว่ามีวิธีสำหรับประเภทนั้นที่ถูกแทนที่หรือไม่?
‫และใช่มี
‫แล้วเราจะให้สิทธิ์ C++ อย่างมีประสิทธิภาพน้อยลงได้อย่างไร และให้ความสามารถในการแทนที่โดยไม่ต้องเปลี่ยนประเภทตัวชี้นั้น
‫ซึ่งไม่จำเป็นเสมอไป
‫อันที่จริง ในหลายกรณี สิ่งนี้เป็นไปไม่ได้ เช่นเดียวกับเมื่อคุณมีคลาสนักแสดงที่คุณกำหนดเอง
‫Unreal ไม่ได้ตั้งค่าตัวชี้ให้ชี้ไปที่คลาสการกระทำเฉพาะของคุณ ซึ่งต้องการให้พวกเขาเปลี่ยนเอ็นจิ้นทั้งหมดทุกครั้งที่คุณแนะนำคลาสใหม่
‫ไม่ นั่นเป็นไปไม่ได้
‫พวกเขามีตัวชี้ไปที่นักแสดงประเภทหนึ่ง
‫ดังนั้นเมื่อพวกเขาเรียกเริ่มเล่น คุณต้องการให้เรียกวิธีการเริ่มเล่นของคุณ
‫จึงต้องเป็นแบบเสมือนจริง
‫และนั่นคือกุญแจสำคัญที่นี่
‫ถ้าเราติด virtual ไว้หน้า method ใน parent class ตอนนี้เป็นสัญญาณ C++ ที่ค้างในวินาทีนี้
‫ถ้าผมเรียก shoot ที่ pointer ของ gun pointer ผมต้องเช็คก่อนว่าไม่ใช่ ปืนพกและวิธีการยิงนี้ถูกแทนที่
‫ดังนั้นถ้าเราวิ่งไปข้างหน้าและวิ่งตอนนี้ คุณจะเห็นว่าเราโดนกระแทกแล้วโดนยา
‫ดังนั้นมันจึงทำงานอย่างที่เราคาดหวังกับ Dynamic Dispatch
‫และนั่นคือคำศัพท์สำหรับสิ่งนี้ โดยพื้นฐานแล้วเราแค่หมายถึงว่า ตรวจสอบว่าสิ่งนี้อยู่ในตัวชี้ประเภทใด
‫และเรียกวิธีการที่เกี่ยวข้อง
‫ขณะนี้มีไวยากรณ์เพิ่มเติมเล็กน้อยที่คุณมักจะมองว่าเป็นการใช้งานและนั่นคือคำสำคัญแทนที่
‫และคุณใส่สิ่งนั้นหลังจากวิธีที่คุณกำลังพยายามแทนที่เป็นเสมือน
‫และโดยพื้นฐานแล้ว คีย์เวิร์ดแทนที่ไม่จำเป็นอย่างยิ่ง และไม่วางเสมือนอีกครั้งกับบางสิ่งในคลาสย่อยของปืน
‫ดังนั้นคุณจึงไม่ต้องใส่เวอร์ชวล แต่ก็ไม่เสียหายที่จะทำ
‫แต่การแทนที่มีประโยชน์อย่างยิ่งเพราะช่วยให้เราแน่ใจว่าเราได้ตั้งชื่อถูกต้องแล้ว
‫ดังนั้น ถ้าฉันกดรัน ทุกอย่างจะทำงานเหมือนเมื่อก่อนเมื่อฉันมีการโอเวอร์ไรด์
‫แต่บอกว่าฉันจำชื่อของวิธีนี้ผิด ดังนั้นฉันจึงไม่ทำการแทนที่
‫และฉันได้เรียกมันว่าไม่ยิง
‫เช่น ฉันคัดลอกชื่อผิด
‫ฉันพิมพ์แทนการคัดลอก
‫ถ้าฉันกดรันตอนนี้ คุณจะเห็นว่าเรามีข้อผิดพลาดแบบเดิมอีกครั้งเพราะเรากำลังพยายามโทรเพื่อยิง
‫เราเขียนทับมันอย่างไม่ถูกต้อง
‫มันกำลังไป ปัง ปัง
‫วิธีที่ฉันสามารถหลีกเลี่ยงสิ่งนี้ได้คือการพูดว่า ฉันกำลังพยายามแทนที่บางสิ่ง
‫ดังนั้นฉันจึงใส่คำสำคัญแทนที่ของฉันที่นี่ และหากฉันพยายามรวบรวมตอนนี้ คุณจะเห็นว่ามันบอกว่าปืนถูกทำเครื่องหมายเป็นการแทนที่
‫แต่ไม่มีวิธีการ ไม่มีวิธีเสมือนสำหรับฉันที่จะลบล้าง ซึ่งในกรณีนี้ฉันสามารถไป อ๋อ ผมพิมพ์ผิดครับ
‫ดังนั้นฉันจะดำเนินการต่อและแก้ไขโค้ดของฉันแล้วทำให้มันกลับมายิงได้
‫และตอนนี้ก็ใช้งานได้ตามที่ฉันตั้งใจไว้
‫ดังนั้นจึงเป็นเพียงการเพิ่มความปลอดภัยเล็กน้อยโดยการแทนที่สิ่งนั้นที่นั่นและทันที
‫นอกจากนี้ยังปกป้องเราจากกรณีที่สิ่งที่เราพยายามจะแทนที่ไม่ใช่เสมือน
‫ถ้าฉันพยายามทำอย่างนั้น คุณจะเห็นว่ามันบอกว่ามันถูกทำเครื่องหมายเป็นการแทนที่ แต่มันไม่ได้ลบล้างเพราะคลาสพาเรนต์นั้นไม่มีฟังก์ชั่นเสมือนสำหรับการยิง
‫หวังว่านี่จะทำให้คุณเห็นภาพรวมว่า C++ ใช้และใช้งานฟังก์ชันเสมือนอย่างไร และทำไมเราจึงต้องชัดเจนเกี่ยวกับสิ่งเหล่านี้
‫ตอนนี้ มาคิดถึงกรณีการใช้งานทั่วไปเพิ่มเติมสำหรับฟังก์ชันเสมือนโดยทั่วไป
‫เราได้เห็นบางส่วนจากเครื่องยนต์แล้ว
‫คุณเคยเห็น virtual ใช้ที่ไหนมาก่อน
‫คุณสามารถจินตนาการถึงการใช้งานได้ที่ไหน?
‫เราเพิ่งเห็นตัวอย่างกรณีการใช้งานที่คุณอาจมีปืนและการแทนที่ที่แตกต่างกันซึ่งใช้การยิงในรูปแบบต่างๆ
‫คุณจะจินตนาการถึงการใช้ฟังก์ชันเสมือนที่แทนที่ฟังก์ชันการทำงานในคลาสพาเรนต์ได้อย่างไร เมื่อคุณนึกถึงคำตอบของคำถามสองข้อนี้
‫ไปตามลิงก์ของการอภิปรายในการบรรยายนี้และโพสต์คำตอบของคุณที่นั่น
‫กรณีการใช้งานและสถานที่ที่คุณเคยใช้มาก่อนและดูว่าคนอื่นคิดอย่างไร
‫บางทีนั่นอาจช่วยให้คุณเข้าใจวิธีการเสมือนจริงมากขึ้น
‫สำหรับการบรรยายครั้งนี้
‫เจอกันใหม่ตอนหน้า เราจะใช้วิธีเสมือนจริงด้วยความโกรธ