﻿1
00:00:04,350 --> 00:00:09,720
‫ในการบรรยายนี้ เราจะพูดถึงวิธีการเสมือนใน C++

2
00:00:09,720 --> 00:00:13,170
‫เราเคยเห็นมันมาก่อน เราเคยใช้มัน แต่เราเข้าใจมันอย่างถ่องแท้หรือเปล่า?

3
00:00:13,170 --> 00:00:14,100
‫มาดูกัน.

4
00:00:14,100 --> 00:00:20,460
‫แนวคิดของเมธอดเสมือนคือช่วยให้เราสามารถแทนที่ฟังก์ชันในคลาสฐานได้

5
00:00:20,460 --> 00:00:29,880
‫เราได้เห็นสิ่งนี้กับสิ่งต่าง ๆ เช่น เริ่มต้น เล่น และ Tic ใน Unreal แต่มาเจาะลึกเรื่องนี้กันดีกว่า และทำความเข้าใจว่าทำไมพวกเขาถึงถูกทำเครื่องหมายเป็นเสมือน

6
00:00:29,880 --> 00:00:38,340
‫มันช่วยให้เราเปลี่ยนฟังก์ชันการทำงานในคลาสพื้นฐานนั้นได้ และมันทำบางสิ่งที่เรียกว่า Dynamic Dispatch ซึ่งเราจะพูดถึงในอีกสักครู่เพื่อให้เข้าใจว่าสิ่งนี้หมายถึงอะไรจริงๆ

7
00:00:38,340 --> 00:00:44,550
‫และทำไมเมธอดเสมือนไม่ใช่ฟังก์ชันเริ่มต้นใน C++ เนื่องจากเป็นภาษาอื่นๆ มากมาย เช่น

8
00:00:44,550 --> 00:00:50,820
‫C Sharp

9
00:00:50,820 --> 00:00:52,320
‫ลองมาดูที่นี้

10
00:00:52,440 --> 00:00:59,910
‫ฉันจะทำสิ่งนี้ในเว็บไซต์ CPP dot S-H เพื่อที่เราจะได้ไม่อยู่ใน Unreal ที่นี่เลย

11
00:00:59,910 --> 00:01:06,090
‫เรากำลังมองหาฟังก์ชันดิบ C++ เพื่อให้คุณเข้าใจคุณลักษณะภาษานี้และวิธีการทำงาน

12
00:01:06,150 --> 00:01:10,680
‫ตอนนี้ อย่างแรกที่ฉันจะทำคือ ไปข้างหน้าและล้างวิธีการหลัก

13
00:01:10,680 --> 00:01:19,680
‫และในกรณีการใช้งานของเรา เราจะคิดถึงคลาสสำหรับปืน เนื่องจากนี่เป็นกรณีการใช้งานทั่วไปสำหรับเกม

14
00:01:19,680 --> 00:01:31,860
‫มาดูคลาสที่เรียกมันว่า gun กันอย่างตรงไปตรงมา แล้วเราจะให้เนื้อหาของคลาสนี้เป็นแบบสาธารณะและเป็นวิธีการยิงแบบเป็นโมฆะ

15
00:01:32,520 --> 00:01:39,310
‫และฉันจะดำเนินการต่อและประกาศเนื้อหาของวิธีการถ่ายภาพนี้ตรงนี้เพื่อให้ทุกอย่างเรียบง่ายมาก

16
00:01:39,330 --> 00:01:44,550
‫อีกอย่าง คุณสามารถทำสิ่งนี้ได้ หากคุณไม่เคยเห็นสิ่งนี้มาก่อน แต่โดยทั่วไปแล้ว เราต้องการทำสิ่งต่าง

17
00:01:44,550 --> 00:01:49,770
‫ๆ ในไฟล์ C++ แยกต่างหากเพื่อแยกสิ่งต่าง ๆ ออกจากกัน เพื่อให้เวลาในการรวบรวมเร็วขึ้นเป็นต้น

18
00:01:49,770 --> 00:01:55,290
‫แต่ในที่นี้เป็นเพียงตัวอย่างของเล่น ไม่เป็นไร เราจะทำ STD C ออกมา

19
00:01:55,290 --> 00:02:04,980
‫ดังนั้นการใช้ C ++ เป็นสตริงเอาต์พุตและเราจะเริ่มต้นเมื่อเราเรียกวิธีนี้แล้วเราจะสิ้นสุดบรรทัด

20
00:02:05,570 --> 00:02:07,850
‫และนั่นคือร่างกายของวิธีการถ่ายภาพของเรา

21
00:02:07,850 --> 00:02:11,720
‫และเราสามารถปิดท้ายชั้นเรียนด้วยเครื่องหมายปีกกาและอัฒภาค

22
00:02:11,960 --> 00:02:14,750
‫มาใช้คลาสนี้กันต่อเถอะ

23
00:02:14,750 --> 00:02:25,910
‫ฉันจะสร้างตัวแปรปืนของฉันใน main และฉันจะเรียก gun dot shoot ของฉันและมาดูกันว่าทุกอย่างทำงานที่นี่ตามที่ควรจะเป็นหรือไม่

24
00:02:25,940 --> 00:02:28,070
‫กดปุ่มวิ่งแล้วปัง

25
00:02:28,160 --> 00:02:30,530
‫กำลังเรียกวิธีการตามที่เราคาดหวัง

26
00:02:30,980 --> 00:02:39,470
‫จะเกิดอะไรขึ้นถ้าฉันต้องการขยายปืนและบางทีอาจทำปืนไรเฟิลหรือปืนพก?

27
00:02:39,470 --> 00:02:40,420
‫เรียกมันว่าปืนพก

28
00:02:40,430 --> 00:02:47,180
‫ดังนั้นปืนพกระดับคลาสจึงเป็นมรดกจากปืนซึ่งจะทำอย่างนี้

29
00:02:47,180 --> 00:02:51,530
‫และถ้าคุณไม่เคยเห็นสิ่งนี้มาก่อนเพราะคุณอาจไม่เคยเขียนสิ่งนี้มาก่อน

30
00:02:51,530 --> 00:02:56,330
‫คุณจะต้องทำมรดกสาธารณะจากปืนเพื่อให้คลาสอื่นเห็นว่าคุณได้รับมรดกจากปืน

31
00:02:56,600 --> 00:03:05,540
‫จากนั้นเราก็ทำในส่วนสาธารณะ เราอาจต้องการสร้างวิธีการยิงของเราเองสำหรับปืนพกที่จะมาแทนที่ฟังก์ชันนี้

32
00:03:05,540 --> 00:03:13,220
‫และแทนที่จะพิมพ์ปังในตอนท้าย เราต้องการพิมพ์เม็ดยาเพราะเป็นปืนที่เล็กกว่า มันให้เสียงที่เล็กกว่า

33
00:03:13,220 --> 00:03:17,420
‫และนั่นคือวิธีการยิงของเราที่นั่น

34
00:03:17,420 --> 00:03:20,150
‫และขอปิดชั้นเรียนที่นั่น

35
00:03:20,360 --> 00:03:23,300
‫และสิ่งที่เราอยากทำคือสร้างปืนพกให้ตัวเอง

36
00:03:23,300 --> 00:03:28,010
‫ดังนั้นปืนพกปืนพกของฉันในวิธีหลักที่นี่

37
00:03:28,670 --> 00:03:34,010
‫และเนื่องจากสิ่งเหล่านี้มีอยู่แล้วในวิธีหลัก เราจึงไม่ได้ใช้พอยน์เตอร์

38
00:03:34,010 --> 00:03:38,450
‫นั่นเป็นเหตุผลที่เราใช้ตัวดำเนินการยิงที่นี่แทนลูกศร

39
00:03:38,750 --> 00:03:42,260
‫ดังนั้นปืนพกของฉันจึงไม่ยิง

40
00:03:42,260 --> 00:03:43,460
‫มาดูกันว่ามันทำอะไรได้บ้าง

41
00:03:43,610 --> 00:03:47,280
‫ฉันคาดหวังว่ามันจะพิมพ์ PPU ซึ่งมันทำ

42
00:03:47,300 --> 00:03:47,930
‫เย็น.

43
00:03:48,260 --> 00:03:51,530
‫เอาล่ะ เรามาลบวิธีการของเราที่กำลังเรียกกัน

44
00:03:51,530 --> 00:03:57,050
‫ยิงไปที่สิ่งเหล่านี้โดยตรงและมาดูกันว่าสิ่งต่าง ๆ จะเป็นอย่างไรด้วยตัวชี้

45
00:03:57,290 --> 00:04:01,880
‫ฉันจะสร้างตัวชี้ปืนที่เรียกว่าปืน

46
00:04:02,660 --> 00:04:03,640
‫ปีเตอร์.

47
00:04:04,570 --> 00:04:06,910
‫และในบรรทัดถัดไป ผมสามารถทำได้ในบรรทัดเดียวกัน

48
00:04:06,910 --> 00:04:08,890
‫แต่เพื่อความเรียบง่าย ฉันจะทำในบรรทัดถัดไป

49
00:04:08,890 --> 00:04:15,790
‫ฉันจะตั้งค่าตัวชี้ปืนให้ชี้ไปที่ที่อยู่นั่นคือที่อยู่ของผู้ปฏิบัติงาน

50
00:04:15,790 --> 00:04:18,310
‫ที่อยู่ของตัวแปรปืนของฉัน

51
00:04:18,580 --> 00:04:23,830
‫และเนื่องจากนี่คือตัวชี้ เราจึงต้องใช้ตัวดำเนินการลูกศรเพื่อเรียกวิธีการยิง

52
00:04:23,830 --> 00:04:30,400
‫ดังนั้นฉันจะเรียกปืนของฉันมาคลิกวิ่งและเราก็ได้รับผลที่นั่น

53
00:04:30,400 --> 00:04:31,120
‫เย็น.

54
00:04:31,210 --> 00:04:34,450
‫จะเกิดอะไรขึ้นถ้าฉันทำสิ่งเดียวกัน

55
00:04:34,450 --> 00:04:40,840
‫แต่แทนที่จะตั้งค่าตัวชี้ปืนให้ชี้ไปที่ปืนของฉัน ฉันตั้งค่าให้ชี้ไปที่ปืนพกของฉัน

56
00:04:40,990 --> 00:04:42,550
‫ไปข้างหน้าและวิ่งในขณะนี้

57
00:04:42,880 --> 00:04:43,240
‫ตกลง.

58
00:04:43,240 --> 00:04:45,190
‫นั่นเป็นพฤติกรรมที่น่าสนใจที่นั่น

59
00:04:45,190 --> 00:04:51,880
‫สิ่งที่เกิดขึ้นที่นี่คือการเรียกวิธีการแรกนี้ในทั้งสองกรณี

60
00:04:51,880 --> 00:04:55,510
‫เหตุใดจึงไม่เรียกวิธีการยิงครั้งที่สองนี้

61
00:04:55,510 --> 00:04:58,030
‫เรามีปืนพกที่นี่เป็นตัวชี้

62
00:04:58,300 --> 00:05:05,500
‫จะเกิดอะไรขึ้นหากคุณไม่มีเมธอดเสมือน โดยค่าเริ่มต้น C++ จะใช้ประเภทของพอยน์เตอร์ของคุณ

63
00:05:05,500 --> 00:05:07,960
‫ซึ่งเป็นตัวชี้ปืน

64
00:05:07,960 --> 00:05:11,890
‫จำไว้ว่ามันจะใช้ประเภทนั้นเพื่อค้นหาวิธีการโทร

65
00:05:11,890 --> 00:05:18,130
‫ดังนั้นมันจะไปและเรียกวิธีการยิงนี้ที่ด้านบนมากกว่าวิธีการแทนที่ในปืนพก

66
00:05:18,130 --> 00:05:25,630
‫เพื่อที่จะเรียกการแทนที่และวิธีการในปืนพก มันจะต้องเรียกว่ามันจะต้องมีตัวชี้แบบปืนพก

67
00:05:25,960 --> 00:05:27,520
‫ตอนนี้ก็ดีแล้ว

68
00:05:27,520 --> 00:05:29,350
‫และคุณจะเห็นว่าทำไมพวกเขาถึงทำเช่นนี้

69
00:05:29,350 --> 00:05:30,430
‫เพื่อประสิทธิภาพ

70
00:05:30,430 --> 00:05:32,410
‫C ++ นั้นเกี่ยวกับประสิทธิภาพ

71
00:05:32,410 --> 00:05:40,600
‫หากมีบางสิ่งที่จะเสียค่าใช้จ่ายมากขึ้นเมื่อคอมไพล์ เมื่อมันรัน C++ จะไม่ทำโดยค่าเริ่มต้น เว้นแต่คุณจะขอให้ทำ

72
00:05:40,630 --> 00:05:47,620
‫ดังนั้นมันจึงง่ายมากสำหรับ C++ ในการค้นหาและใช้งาน นี่คือตัวชี้ปืน ฉันจะเรียกวิธีนี้ว่าปืนชี้

73
00:05:47,620 --> 00:05:50,080
‫และนี่คือที่มาของ Dynamic Dispatch

74
00:05:50,080 --> 00:05:54,070
‫คำศัพท์แฟนซีนี้โดยพื้นฐานแล้วหมายความว่าเราไม่ต้องการให้ทำเช่นนั้น

75
00:05:54,070 --> 00:05:59,950
‫สิ่งที่เราต้องการให้ทำคือพูดว่า เดี๋ยวก่อน อะไรกันแน่ที่เก็บไว้ในตัวชี้ปืนนั้น

76
00:05:59,950 --> 00:06:02,140
‫ของจริงมีแบบไหนบ้าง?

77
00:06:02,380 --> 00:06:06,250
‫และประเภทที่แท้จริงที่เรารู้ก็คือมันเป็นปืนพกแบบ

78
00:06:06,250 --> 00:06:12,520
‫ดังนั้นเราจึงต้องถามตัวเองว่ามีวิธีสำหรับประเภทนั้นที่ถูกแทนที่หรือไม่?

79
00:06:12,520 --> 00:06:13,600
‫และใช่มี

80
00:06:13,600 --> 00:06:20,230
‫แล้วเราจะให้สิทธิ์ C++ อย่างมีประสิทธิภาพน้อยลงได้อย่างไร และให้ความสามารถในการแทนที่โดยไม่ต้องเปลี่ยนประเภทตัวชี้นั้น

81
00:06:20,230 --> 00:06:26,110
‫ซึ่งไม่จำเป็นเสมอไป

82
00:06:26,110 --> 00:06:32,470
‫อันที่จริง ในหลายกรณี สิ่งนี้เป็นไปไม่ได้ เช่นเดียวกับเมื่อคุณมีคลาสนักแสดงที่คุณกำหนดเอง

83
00:06:32,590 --> 00:06:41,290
‫Unreal ไม่ได้ตั้งค่าตัวชี้ให้ชี้ไปที่คลาสการกระทำเฉพาะของคุณ ซึ่งต้องการให้พวกเขาเปลี่ยนเอ็นจิ้นทั้งหมดทุกครั้งที่คุณแนะนำคลาสใหม่

84
00:06:41,290 --> 00:06:43,120
‫ไม่ นั่นเป็นไปไม่ได้

85
00:06:43,120 --> 00:06:46,360
‫พวกเขามีตัวชี้ไปที่นักแสดงประเภทหนึ่ง

86
00:06:46,360 --> 00:06:51,010
‫ดังนั้นเมื่อพวกเขาเรียกเริ่มเล่น คุณต้องการให้เรียกวิธีการเริ่มเล่นของคุณ

87
00:06:51,010 --> 00:06:52,630
‫จึงต้องเป็นแบบเสมือนจริง

88
00:06:52,630 --> 00:06:54,340
‫และนั่นคือกุญแจสำคัญที่นี่

89
00:06:54,340 --> 00:07:02,500
‫ถ้าเราติด virtual ไว้หน้า method ใน parent class ตอนนี้เป็นสัญญาณ C++ ที่ค้างในวินาทีนี้

90
00:07:02,500 --> 00:07:14,350
‫ถ้าผมเรียก shoot ที่ pointer ของ gun pointer ผมต้องเช็คก่อนว่าไม่ใช่ ปืนพกและวิธีการยิงนี้ถูกแทนที่

91
00:07:14,350 --> 00:07:19,390
‫ดังนั้นถ้าเราวิ่งไปข้างหน้าและวิ่งตอนนี้ คุณจะเห็นว่าเราโดนกระแทกแล้วโดนยา

92
00:07:19,420 --> 00:07:24,070
‫ดังนั้นมันจึงทำงานอย่างที่เราคาดหวังกับ Dynamic Dispatch

93
00:07:24,070 --> 00:07:30,370
‫และนั่นคือคำศัพท์สำหรับสิ่งนี้ โดยพื้นฐานแล้วเราแค่หมายถึงว่า ตรวจสอบว่าสิ่งนี้อยู่ในตัวชี้ประเภทใด

94
00:07:30,370 --> 00:07:33,430
‫และเรียกวิธีการที่เกี่ยวข้อง

95
00:07:33,940 --> 00:07:40,450
‫ขณะนี้มีไวยากรณ์เพิ่มเติมเล็กน้อยที่คุณมักจะมองว่าเป็นการใช้งานและนั่นคือคำสำคัญแทนที่

96
00:07:40,450 --> 00:07:45,520
‫และคุณใส่สิ่งนั้นหลังจากวิธีที่คุณกำลังพยายามแทนที่เป็นเสมือน

97
00:07:45,790 --> 00:07:56,200
‫และโดยพื้นฐานแล้ว คีย์เวิร์ดแทนที่ไม่จำเป็นอย่างยิ่ง และไม่วางเสมือนอีกครั้งกับบางสิ่งในคลาสย่อยของปืน

98
00:07:56,200 --> 00:07:59,350
‫ดังนั้นคุณจึงไม่ต้องใส่เวอร์ชวล แต่ก็ไม่เสียหายที่จะทำ

99
00:07:59,560 --> 00:08:07,030
‫แต่การแทนที่มีประโยชน์อย่างยิ่งเพราะช่วยให้เราแน่ใจว่าเราได้ตั้งชื่อถูกต้องแล้ว

100
00:08:07,030 --> 00:08:10,690
‫ดังนั้น ถ้าฉันกดรัน ทุกอย่างจะทำงานเหมือนเมื่อก่อนเมื่อฉันมีการโอเวอร์ไรด์

101
00:08:10,690 --> 00:08:17,290
‫แต่บอกว่าฉันจำชื่อของวิธีนี้ผิด ดังนั้นฉันจึงไม่ทำการแทนที่

102
00:08:17,290 --> 00:08:19,490
‫และฉันได้เรียกมันว่าไม่ยิง

103
00:08:19,870 --> 00:08:22,750
‫เช่น ฉันคัดลอกชื่อผิด

104
00:08:22,750 --> 00:08:24,520
‫ฉันพิมพ์แทนการคัดลอก

105
00:08:24,520 --> 00:08:29,230
‫ถ้าฉันกดรันตอนนี้ คุณจะเห็นว่าเรามีข้อผิดพลาดแบบเดิมอีกครั้งเพราะเรากำลังพยายามโทรเพื่อยิง

106
00:08:29,230 --> 00:08:32,350
‫เราเขียนทับมันอย่างไม่ถูกต้อง

107
00:08:32,350 --> 00:08:33,820
‫มันกำลังไป ปัง ปัง

108
00:08:33,910 --> 00:08:37,840
‫วิธีที่ฉันสามารถหลีกเลี่ยงสิ่งนี้ได้คือการพูดว่า ฉันกำลังพยายามแทนที่บางสิ่ง

109
00:08:37,840 --> 00:08:44,170
‫ดังนั้นฉันจึงใส่คำสำคัญแทนที่ของฉันที่นี่ และหากฉันพยายามรวบรวมตอนนี้ คุณจะเห็นว่ามันบอกว่าปืนถูกทำเครื่องหมายเป็นการแทนที่

110
00:08:44,170 --> 00:08:52,360
‫แต่ไม่มีวิธีการ ไม่มีวิธีเสมือนสำหรับฉันที่จะลบล้าง ซึ่งในกรณีนี้ฉันสามารถไป อ๋อ ผมพิมพ์ผิดครับ

111
00:08:52,360 --> 00:08:57,340
‫ดังนั้นฉันจะดำเนินการต่อและแก้ไขโค้ดของฉันแล้วทำให้มันกลับมายิงได้

112
00:08:57,340 --> 00:08:59,320
‫และตอนนี้ก็ใช้งานได้ตามที่ฉันตั้งใจไว้

113
00:08:59,320 --> 00:09:04,150
‫ดังนั้นจึงเป็นเพียงการเพิ่มความปลอดภัยเล็กน้อยโดยการแทนที่สิ่งนั้นที่นั่นและทันที

114
00:09:04,240 --> 00:09:09,170
‫นอกจากนี้ยังปกป้องเราจากกรณีที่สิ่งที่เราพยายามจะแทนที่ไม่ใช่เสมือน

115
00:09:09,190 --> 00:09:19,410
‫ถ้าฉันพยายามทำอย่างนั้น คุณจะเห็นว่ามันบอกว่ามันถูกทำเครื่องหมายเป็นการแทนที่ แต่มันไม่ได้ลบล้างเพราะคลาสพาเรนต์นั้นไม่มีฟังก์ชั่นเสมือนสำหรับการยิง

116
00:09:19,420 --> 00:09:28,330
‫หวังว่านี่จะทำให้คุณเห็นภาพรวมว่า C++ ใช้และใช้งานฟังก์ชันเสมือนอย่างไร และทำไมเราจึงต้องชัดเจนเกี่ยวกับสิ่งเหล่านี้

117
00:09:28,600 --> 00:09:32,890
‫ตอนนี้ มาคิดถึงกรณีการใช้งานทั่วไปเพิ่มเติมสำหรับฟังก์ชันเสมือนโดยทั่วไป

118
00:09:32,890 --> 00:09:34,750
‫เราได้เห็นบางส่วนจากเครื่องยนต์แล้ว

119
00:09:34,750 --> 00:09:37,630
‫คุณเคยเห็น virtual ใช้ที่ไหนมาก่อน

120
00:09:38,450 --> 00:09:40,190
‫คุณสามารถจินตนาการถึงการใช้งานได้ที่ไหน?

121
00:09:40,220 --> 00:09:46,880
‫เราเพิ่งเห็นตัวอย่างกรณีการใช้งานที่คุณอาจมีปืนและการแทนที่ที่แตกต่างกันซึ่งใช้การยิงในรูปแบบต่างๆ

122
00:09:47,300 --> 00:09:55,530
‫คุณจะจินตนาการถึงการใช้ฟังก์ชันเสมือนที่แทนที่ฟังก์ชันการทำงานในคลาสพาเรนต์ได้อย่างไร เมื่อคุณนึกถึงคำตอบของคำถามสองข้อนี้

123
00:09:55,550 --> 00:10:01,290
‫ไปตามลิงก์ของการอภิปรายในการบรรยายนี้และโพสต์คำตอบของคุณที่นั่น

124
00:10:01,310 --> 00:10:06,010
‫กรณีการใช้งานและสถานที่ที่คุณเคยใช้มาก่อนและดูว่าคนอื่นคิดอย่างไร

125
00:10:06,020 --> 00:10:11,250
‫บางทีนั่นอาจช่วยให้คุณเข้าใจวิธีการเสมือนจริงมากขึ้น

126
00:10:11,270 --> 00:10:12,280
‫สำหรับการบรรยายครั้งนี้

127
00:10:12,290 --> 00:10:15,710
‫เจอกันใหม่ตอนหน้า เราจะใช้วิธีเสมือนจริงด้วยความโกรธ

