﻿1
00:00:04,440 --> 00:00:09,690
‫W tym wykładzie będziemy mówić o metodzie wirtualnej w C++.

2
00:00:09,690 --> 00:00:13,110
‫Widzieliśmy to już wcześniej, używaliśmy tego, ale czy w pełni to zrozumieliśmy?

3
00:00:13,110 --> 00:00:13,860
‫Pozwól nam zobaczyć.

4
00:00:14,220 --> 00:00:20,400
‫Zatem idea metody wirtualnej polega na tym, że pozwala nam ona nadpisywać funkcje w klasie bazowej.

5
00:00:20,400 --> 00:00:24,690
‫Widzieliśmy to z takimi rzeczami, jak rozpoczynanie, granie i przyjmowanie Unreal.

6
00:00:25,020 --> 00:00:29,640
‫Przejdźmy jednak dalej i zrozummy, dlaczego są one oznaczone jako wirtualne.

7
00:00:30,030 --> 00:00:38,130
‫Pozwala nam na zmianę funkcjonalności w tej klasie bazowej i robi coś, co nazywa się Dynamic Dispatch, o czym porozmawiamy

8
00:00:38,430 --> 00:00:44,520
‫za chwilę, aby zrozumieć, co to naprawdę oznacza i dlaczego metody wirtualne nie są

9
00:00:44,520 --> 00:00:50,610
‫domyślną funkcjonalnością w C++ tak jak w wielu innych językach, takich jak C Sharp.

10
00:00:50,910 --> 00:00:52,050
‫Więc spójrzmy na to.

11
00:00:52,500 --> 00:00:59,850
‫Będę to robił na stronie CPP dot S-H, żeby w ogóle nie było nas w Unreal.

12
00:00:59,850 --> 00:01:05,130
‫Patrzymy tylko na surową funkcjonalność C++, aby można było zrozumieć tę funkcję języka i sposób jej

13
00:01:05,130 --> 00:01:05,820
‫działania.

14
00:01:06,300 --> 00:01:10,440
‫Teraz pierwszą rzeczą, którą zamierzam tutaj zrobić, jest po prostu wyjaśnienie głównej metody.

15
00:01:10,770 --> 00:01:18,390
‫A w naszym przypadku użycia będziemy myśleć o klasie broni, ponieważ jest to bardzo powszechny przypadek użycia

16
00:01:18,390 --> 00:01:19,380
‫w grach.

17
00:01:19,830 --> 00:01:26,700
‫Przyjrzyjmy się więc klasie, ostudźmy broń dość prosto, a potem będziemy mieć

18
00:01:26,700 --> 00:01:31,560
‫publiczne ciało tej klasy i metodę void shoot.

19
00:01:32,550 --> 00:01:38,400
‫I zamierzam po prostu ogłosić tutaj treść tej metody strzelania, aby wszystko było super

20
00:01:38,400 --> 00:01:39,290
‫proste.

21
00:01:39,300 --> 00:01:41,310
‫Przy okazji, możesz to zrobić, jeśli wcześniej tego nie widziałeś.

22
00:01:41,520 --> 00:01:47,820
‫Ale ogólnie rzecz biorąc, chcemy robić rzeczy w osobnym pliku C++, aby zachować oddzielne rzeczy, aby skrócić czas

23
00:01:47,820 --> 00:01:49,560
‫kompilacji i tak dalej.

24
00:01:49,860 --> 00:01:52,140
‫Ale tutaj, gdzie to tylko przykład zabawki, to jest w porządku.

25
00:01:52,650 --> 00:01:55,260
‫Więc zrobimy SD see out.

26
00:01:55,260 --> 00:01:59,730
‫Używając C++ jako wyjściowego łańcucha znaków i zaczynamy huk.

27
00:02:00,360 --> 00:02:04,710
‫Zasadniczo, kiedy wywołamy tę metodę, a następnie przejdziemy do linii końcowej.

28
00:02:05,630 --> 00:02:07,820
‫I to jest istota naszej metody spadochronowej.

29
00:02:07,820 --> 00:02:11,510
‫I możemy zakończyć klasę nawiasem klamrowym i średnikiem.

30
00:02:12,050 --> 00:02:14,680
‫Więc chodźmy dalej i faktycznie użyjmy tej klasy.

31
00:02:14,690 --> 00:02:23,420
‫Zamierzam utworzyć zmienną mojego pistoletu w main i wywołam strzelanie do pistoletu i zobaczymy, czy wszystko działa

32
00:02:23,420 --> 00:02:25,670
‫tutaj tak, jak powinno.

33
00:02:26,000 --> 00:02:27,830
‫Naciśnij przycisk uruchamiania i huk.

34
00:02:28,210 --> 00:02:30,260
‫To wywołanie metody, jak byśmy się spodziewali.

35
00:02:31,040 --> 00:02:40,220
‫A teraz, co się stanie, jeśli chcę przedłużyć pistolet i być może zrobić karabin lub pistolet, który nazywa się pistoletem.

36
00:02:40,580 --> 00:02:46,970
‫Tak więc pistolet klasy to odziedziczony po pistolecie, który by to zrobił.

37
00:02:47,180 --> 00:02:51,470
‫A jeśli nie widziałeś tego wcześniej, ponieważ prawdopodobnie nie napisałeś tego wcześniej,

38
00:02:51,470 --> 00:02:56,090
‫robisz publiczne dziedziczenie po gunach, aby inne klasy mogły zobaczyć, że dziedziczysz po gunie.

39
00:02:56,720 --> 00:03:04,220
‫A potem robimy w sekcji publicznej, może chcemy stworzyć własną metodę strzelania z pistoletu, która nadpisuje

40
00:03:04,220 --> 00:03:05,510
‫tę funkcjonalność.

41
00:03:05,510 --> 00:03:13,190
‫I zamiast drukować bang na końcu, chcemy wydrukować pigułkę, ponieważ jest to mniejsza broń, wydaje cichszy

42
00:03:13,190 --> 00:03:17,270
‫dźwięk i to jest nasza metoda strzelania.

43
00:03:17,450 --> 00:03:19,910
‫I zakończmy tam zajęcia.

44
00:03:20,510 --> 00:03:23,290
‫A my chcemy stworzyć sobie pistolet.

45
00:03:23,300 --> 00:03:27,740
‫Więc wystrzel mój pistolet w głównej metodzie tutaj.

46
00:03:28,640 --> 00:03:33,980
‫A ponieważ po prostu istnieją tutaj, bezpośrednio w głównej metodzie, nie używamy do nich wskaźników.

47
00:03:33,980 --> 00:03:38,240
‫Dlatego używamy tutaj operatora kropki zamiast strzałki.

48
00:03:38,840 --> 00:03:42,020
‫Więc mój pistolet strzela.

49
00:03:42,200 --> 00:03:43,190
‫Zobaczmy, co to robi.

50
00:03:43,670 --> 00:03:47,030
‫Spodziewam się, że wypisze ppu, co robi.

51
00:03:47,320 --> 00:03:47,690
‫Fajny.

52
00:03:48,230 --> 00:03:51,470
‫Ok, więc usuńmy nasze metody, które się wywołują.

53
00:03:51,470 --> 00:03:56,810
‫Strzelaj bezpośrednio do nich i zobaczmy, jak zachowywałyby się rzeczy ze wskaźnikiem.

54
00:03:57,410 --> 00:04:01,580
‫Więc mam zamiar stworzyć wskaźnik pistoletu zwany pistoletem.

55
00:04:02,640 --> 00:04:03,420
‫Piotr.

56
00:04:04,600 --> 00:04:08,440
‫A w następnej linii mógłbym to zrobić w tej samej linii, ale dla uproszczenia zrobię to w następnej

57
00:04:08,440 --> 00:04:08,860
‫linii.

58
00:04:08,860 --> 00:04:16,030
‫Ustawię ten wskaźnik pistoletu tak, aby wskazywał na adres adresu operatora, adres

59
00:04:16,030 --> 00:04:18,070
‫zmiennej mojego pistoletu.

60
00:04:18,670 --> 00:04:23,710
‫A ponieważ jest to wskaźnik, musimy użyć operatora strzałki, aby wywołać metodę strzelania.

61
00:04:23,830 --> 00:04:26,410
‫Więc zawołam strzelać z mojej broni.

62
00:04:26,830 --> 00:04:30,310
‫Kliknijmy biegnij i tam otrzymamy huk.

63
00:04:30,370 --> 00:04:30,850
‫Fajny.

64
00:04:31,330 --> 00:04:34,420
‫Co się stanie, jeśli zrobię to samo?

65
00:04:34,420 --> 00:04:40,570
‫Ale zamiast ustawić pistolet skierowany na mój pistolet, ustawiłem go tak, aby był skierowany na mój pistolet.

66
00:04:40,960 --> 00:04:42,280
‫Chodźmy dalej i wciśnij biegnij teraz.

67
00:04:42,850 --> 00:04:43,200
‫Dobra.

68
00:04:43,210 --> 00:04:44,950
‫To ciekawe zachowanie.

69
00:04:45,340 --> 00:04:51,610
‫To, co się tutaj dzieje, to wywołanie tej pierwszej metody w obu przypadkach.

70
00:04:52,000 --> 00:04:55,450
‫Dlaczego więc ta druga metoda strzelania nie została wywołana?

71
00:04:55,450 --> 00:04:57,790
‫Mamy tu pistolet jako wskazówkę.

72
00:04:58,390 --> 00:05:05,440
‫Cóż, jeśli nie masz metody wirtualnej, domyślnie C++ użyje typu twojego wskaźnika,

73
00:05:05,440 --> 00:05:07,900
‫którym jest wskaźnik pistoletu.

74
00:05:07,900 --> 00:05:11,820
‫Pamiętaj, że użyje tego typu, aby znaleźć metodę do wywołania.

75
00:05:11,830 --> 00:05:17,920
‫Więc pójdzie i wywoła tę metodę strzelania z góry, a nie nadpisaną metodę w pistolecie.

76
00:05:18,190 --> 00:05:22,780
‫Aby wywołać nadpisaną metodę w pistolecie, musiałby wywołać.

77
00:05:22,780 --> 00:05:25,390
‫Musiałby mieć wskaźnik typu pistolet.

78
00:05:26,020 --> 00:05:27,490
‫Teraz w porządku.

79
00:05:27,490 --> 00:05:29,320
‫I możesz zobaczyć, dlaczego to robią.

80
00:05:29,320 --> 00:05:30,370
‫To dla wydajności.

81
00:05:30,370 --> 00:05:32,200
‫W C++ chodzi o wydajność.

82
00:05:32,500 --> 00:05:39,220
‫Jeśli coś będzie kosztować więcej, gdy jest skompilowane, gdy działa, to C++ nie zrobi tego domyślnie, chyba że

83
00:05:39,220 --> 00:05:40,420
‫o to poprosisz.

84
00:05:40,750 --> 00:05:46,240
‫Więc C++ bardzo łatwo jest wyszukać i przejść. Cóż, to jest wskaźnik pistoletu, więc nazwę tę

85
00:05:46,240 --> 00:05:47,320
‫metodę wskaźnika pistoletu.

86
00:05:47,740 --> 00:05:50,040
‫I tu właśnie pojawia się funkcja Dynamic Dispatch.

87
00:05:50,050 --> 00:05:53,890
‫Ten fantazyjny termin zasadniczo oznacza, że nie chcemy, aby to robiło.

88
00:05:54,160 --> 00:05:59,910
‫To, czego chcemy, to powiedzieć, poczekać chwilę, co tak naprawdę jest przechowywane w tym wskaźniku pistoletu?

89
00:05:59,920 --> 00:06:01,960
‫Jaki jest tam prawdziwy typ?

90
00:06:02,410 --> 00:06:06,040
‫A prawdziwy typ, z którego zdajemy sobie sprawę, to pistolet.

91
00:06:06,310 --> 00:06:12,490
‫Musimy więc zadać sobie pytanie, czy istnieje metoda dla tego typu, która jest pomijana?

92
00:06:12,490 --> 00:06:13,570
‫I tak, jest.

93
00:06:13,600 --> 00:06:20,080
‫Jak więc dać C++ pozwolenie na bycie choć trochę mniej wydajnym i dać nam możliwość

94
00:06:20,290 --> 00:06:26,050
‫nadpisania bez konieczności zmiany tego typu wskaźnika, co nie zawsze jest możliwe.

95
00:06:26,050 --> 00:06:31,660
‫W rzeczywistości w wielu przypadkach nie jest to możliwe, tak jak w przypadku posiadania własnej, niestandardowej aktywnej

96
00:06:31,660 --> 00:06:32,170
‫klasy.

97
00:06:32,650 --> 00:06:38,350
‫Unreal nie ma ustawionego wskaźnika wskazującego na twoją konkretną klasę, co wymagałoby od nich zmiany całego silnika

98
00:06:38,350 --> 00:06:41,110
‫za każdym razem, gdy wprowadzasz nową klasę.

99
00:06:41,350 --> 00:06:42,910
‫Nie, to po prostu niemożliwe.

100
00:06:43,210 --> 00:06:46,210
‫Mają wskaźnik do czegoś w rodzaju aktu gwiazdy.

101
00:06:46,450 --> 00:06:50,950
‫Więc kiedy nazywają Begin Play, chciałeś wywołać metodę Begin Play.

102
00:06:50,950 --> 00:06:52,450
‫Musi więc być wirtualny.

103
00:06:52,690 --> 00:06:54,160
‫I to jest tutaj klucz.

104
00:06:54,400 --> 00:07:02,440
‫Jeśli trzymamy virtual przed metodą w klasie nadrzędnej, to teraz sygnalizuje C++, że zawiesza się na sekundę, jeśli

105
00:07:02,440 --> 00:07:09,970
‫wywołuję shoot na wskaźniku typu gun pointer, muszę sprawdzić, czy tak nie jest, na przykład ,

106
00:07:10,150 --> 00:07:14,080
‫pistolet i że ta metoda strzelania została pominięta.

107
00:07:14,500 --> 00:07:19,180
‫Więc jeśli pójdziemy dalej i uderzymy teraz, zobaczycie, że dostaniemy huk, a potem pue.

108
00:07:19,570 --> 00:07:23,800
‫Działa to więc tak, jak oczekiwalibyśmy z dynamiczną wysyłką.

109
00:07:24,100 --> 00:07:30,340
‫I to jest termin dla tej rzeczy, w której zasadniczo chodzi nam po prostu o sprawdzenie, jakiego rodzaju to naprawdę

110
00:07:30,340 --> 00:07:33,160
‫jest trzymane we wskaźniku i wywołanie odpowiedniej metody.

111
00:07:34,030 --> 00:07:39,670
‫Teraz jest trochę dodatkowej składni, której często używamy, a jest to słowo kluczowe

112
00:07:39,670 --> 00:07:40,420
‫override.

113
00:07:40,420 --> 00:07:45,280
‫I umieszczasz to po metodzie, którą próbujesz zastąpić jako wirtualną.

114
00:07:45,910 --> 00:07:53,590
‫I w zasadzie słowo kluczowe override nie jest bezwzględnie konieczne, podobnie jak ponowne umieszczanie wirtualnego przeciwko

115
00:07:53,590 --> 00:07:56,160
‫czemuś z potomnej klasy broni.

116
00:07:56,170 --> 00:07:59,140
‫Więc nie musisz umieszczać wirtualnego, ale nie zaszkodzi to zrobić.

117
00:07:59,650 --> 00:08:06,490
‫Ale override jest szczególnie pomocne, ponieważ pozwala nam tylko upewnić się, że nasze nazewnictwo jest

118
00:08:06,490 --> 00:08:07,000
‫poprawne.

119
00:08:07,000 --> 00:08:10,480
‫Więc jeśli nacisnę bieg, wszystko działa jak poprzednio, gdy mam nadpisanie.

120
00:08:10,810 --> 00:08:17,230
‫Ale powiedzmy, że przez pomyłkę pomyliłem nazwę tej metody, więc nie robię nadpisania.

121
00:08:17,230 --> 00:08:20,680
‫Na przykład nazwałem to strzelanką do notatek.

122
00:08:20,950 --> 00:08:22,720
‫Źle skopiowałem nazwę.

123
00:08:22,720 --> 00:08:24,280
‫Wpisałem to zamiast kopiować.

124
00:08:24,610 --> 00:08:28,960
‫Jeśli teraz nacisnę bieg, to znowu mamy ten sam błąd, ponieważ staramy się strzelać spokojnie.

125
00:08:29,320 --> 00:08:32,170
‫Pomyłkowo nadpisaliśmy to niepoprawnie.

126
00:08:32,410 --> 00:08:33,550
‫Będzie huk, huk.

127
00:08:34,060 --> 00:08:37,780
‫Więc sposobem, w jaki mógłbym tego uniknąć, jest powiedzenie: Cóż, próbuję coś przesłonić.

128
00:08:37,780 --> 00:08:43,750
‫Więc umieściłem tutaj moje słowo kluczowe override, a jeśli spróbuję je teraz skompilować, zobaczysz, że mówi, że strzelanka

129
00:08:43,750 --> 00:08:49,510
‫jest oznaczona jako override, ale nie ma metody, żadnej wirtualnej metody, którą mógłbym zastąpić, w takim przypadku

130
00:08:49,510 --> 00:08:52,360
‫mogę przejść , O tak, błędnie to wpisałem.

131
00:08:52,360 --> 00:08:57,070
‫Więc zamierzam iść dalej i poprawić swój kod i po prostu wrócić do strzelania.

132
00:08:57,460 --> 00:08:59,290
‫A teraz działa tak, jak zamierzałem.

133
00:08:59,290 --> 00:09:04,130
‫Więc to tylko trochę dodatkowego bezpieczeństwa, umieszczając to obejście tam i natychmiast to.

134
00:09:04,180 --> 00:09:09,130
‫Chroniłoby nas również przed przypadkiem, w którym to, co próbujemy obejść, nie jest wirtualne.

135
00:09:09,130 --> 00:09:14,620
‫Jeśli spróbuję to zrobić, zobaczysz, że jest to oznaczone jako nadpisanie, ale nie nadpisuje,

136
00:09:14,620 --> 00:09:19,210
‫ponieważ ta klasa nadrzędna nie ma wirtualnej funkcji do strzelania.

137
00:09:19,390 --> 00:09:25,540
‫Miejmy więc nadzieję, że jest to pewien przegląd tego, w jaki sposób C++ używa i implementuje funkcje wirtualne i dlaczego

138
00:09:25,540 --> 00:09:28,090
‫musimy być tak jednoznaczni w ich przypadku.

139
00:09:28,690 --> 00:09:32,860
‫Zastanówmy się teraz nad kilkoma innymi przypadkami użycia funkcji wirtualnych w ogóle.

140
00:09:32,860 --> 00:09:34,690
‫Widzieliśmy już niektóre z silnika.

141
00:09:34,690 --> 00:09:37,360
‫Gdzie widziałeś wcześniej używany wirtualny?

142
00:09:38,510 --> 00:09:40,150
‫Gdzie możesz sobie wyobrazić jego użycie?

143
00:09:40,160 --> 00:09:45,050
‫Właśnie widzieliśmy przykład użycia, w którym możesz mieć broń i różne nadpisania tego, które

144
00:09:45,050 --> 00:09:46,640
‫strzelają na różne sposoby.

145
00:09:47,390 --> 00:09:53,600
‫Jak inaczej można sobie wyobrazić użycie funkcji wirtualnych do zastąpienia funkcjonalności w klasach nadrzędnych?

146
00:09:53,600 --> 00:09:58,190
‫Kiedy pomyślałeś o odpowiedzi na te dwa pytania, przejdź do linku do dyskusji

147
00:09:58,190 --> 00:10:00,890
‫w tym wykładzie i opublikuj swoją odpowiedź.

148
00:10:00,890 --> 00:10:05,810
‫Przedstawiają przypadki użycia i miejsca, w których korzystałeś z nich wcześniej, i zobacz, co wymyślili inni ludzie.

149
00:10:06,080 --> 00:10:11,150
‫Może to pomoże ci utrwalić zrozumienie metod wirtualnych.

150
00:10:11,240 --> 00:10:12,230
‫To tyle na ten wykład.

151
00:10:12,230 --> 00:10:15,500
‫Do zobaczenia w następnym, gdzie będziemy w gniewie używać wirtualnych metod.

