﻿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
‫このことは､ Unreal の begin､ play､ tic などで確認しましたが､ さらに詳しく､ なぜこれらが仮想とマークされるのかを理解しましょう｡

6
00:00:29,880 --> 00:00:44,550
‫これは動的ディスパッチと呼ばれるもので､ この本当の意味と､ なぜCシャープなど他の多くの言語のように仮想メソッドがC++のデフォルト機能でないのかを理解するために､

7
00:00:44,550 --> 00:00:50,820
‫これから少し話をします｡

8
00:00:50,820 --> 00:00:52,320
‫では､ これを見てみましょう｡

9
00:00:52,440 --> 00:00:59,910
‫CPP dot S-Hのホームページで行うので､ ここではUnrealでは全くありません｡

10
00:00:59,910 --> 00:01:06,090
‫この言語機能とその仕組みを理解していただくために､ 生のC++の機能を見ているだけなのです｡

11
00:01:06,150 --> 00:01:10,680
‫さて､ ここで最初にやることは､ mainメソッドをクリアすることです｡

12
00:01:10,680 --> 00:01:19,680
‫今回のユースケースでは､ 銃のクラスについて考えてみます｡ これは､ ゲームでは非常に一般的なユースケースです｡

13
00:01:19,680 --> 00:01:26,760
‫では､ かなり素直にit gunというクラスを見てみましょう｡ そして､ このクラスの本体をpublicにして､

14
00:01:26,760 --> 00:01:31,860
‫void shootメソッドを用意します｡

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 outをします｡

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にmy gun変数を作成し､ my 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
‫つまり､ pistolクラスはgunを継承したもので､ 次のようなことになる｡

29
00:02:47,180 --> 00:02:51,530
‫そして､ もしあなたがこれを見たことがないのであれば､ おそらく以前に必ずしもこれを書いたことがないのでしょうが､

30
00:02:51,530 --> 00:02:56,330
‫他のクラスがgunから継承していることがわかるように､ gunからpublic継承を行うでしょう｡

31
00:02:56,600 --> 00:03:05,540
‫そして､ publicセクションで､ この機能をオーバーライドするピストル用の独自のshootメソッドを作成したいと思います｡

32
00:03:05,540 --> 00:03:17,420
‫銃が小さいので､ 音も小さくなります｡

33
00:03:17,420 --> 00:03:20,150
‫そして､ そこで授業の締めくくりとしましょう｡

34
00:03:20,360 --> 00:03:23,300
‫そして､ 私たちがやりたいことは､ 自分たちでピストルを作ることです｡

35
00:03:23,300 --> 00:03:28,010
‫だから､ ここのメインメソッドでピストル・マイ・ピストル｡

36
00:03:28,670 --> 00:03:34,010
‫また､ これらはメインメソッド上に存在するだけなので､ ポインターは使用していません｡

37
00:03:34,010 --> 00:03:38,450
‫そのため､ ここでは矢印ではなく､ ショット演算子を使用しています｡

38
00:03:38,750 --> 00:03:42,260
‫だから､ 私のピストルは撃てない｡

39
00:03:42,260 --> 00:03:43,460
‫その効果を見てみましょう｡

40
00:03:43,610 --> 00:03:47,280
‫PPUをプリントしてくれる､ と期待することにします｡

41
00:03:47,300 --> 00:03:47,930
‫かっこいい｡

42
00:03:48,260 --> 00:03:51,530
‫では､ 呼び出されているメソッドを削除してみましょう｡

43
00:03:51,530 --> 00:03:57,050
‫これを直接撮影して､ ポインターを使った場合の挙動を見てみましょう｡

44
00:03:57,290 --> 00:04:01,880
‫そこで､ Gunという銃のポインターを作ってみます｡

45
00:04:02,660 --> 00:04:03,640
‫ピーター

46
00:04:04,570 --> 00:04:06,910
‫そして､ 次のラインでは､ 同じラインでできるようになりました｡

47
00:04:06,910 --> 00:04:08,890
‫でも､ わかりやすくするために､ 次の行でやることにします｡

48
00:04:08,890 --> 00:04:18,310
‫その銃のポインターを､ operatorのアドレス､ つまりmy gun変数のアドレスを指すように設定するんだ｡

49
00:04:18,580 --> 00:04:23,830
‫そして､ これはポインターなので､ 矢印演算子を使ってshootメソッドを呼び出す必要があります｡

50
00:04:23,830 --> 00:04:30,400
‫そこで､ 私の銃でシュートを呼び出し､ 実行をクリックすると､ そこに結果としてバーンが表示されます｡

51
00:04:30,400 --> 00:04:31,120
‫かっこいい｡

52
00:04:31,210 --> 00:04:34,450
‫さて､ 私が同じことをしたらどうなるでしょうか｡

53
00:04:34,450 --> 00:04:40,840
‫しかし､ 銃のポインターを自分の銃を指すように設定するのではなく､ ピストルを指すように設定したのです｡

54
00:04:40,990 --> 00:04:42,550
‫さあ､ 今すぐ実行を押してみましょう｡

55
00:04:42,880 --> 00:04:43,240
‫なるほど｡

56
00:04:43,240 --> 00:04:45,190
‫それはそれで面白い行動ですね｡

57
00:04:45,190 --> 00:04:51,880
‫ここで起こっていることは､ 両方のインスタンスでこの最初のメソッドを呼び出していることです｡

58
00:04:51,880 --> 00:04:55,510
‫では､ なぜこの2回目の撮影方法が呼ばれないのでしょうか？

59
00:04:55,510 --> 00:04:58,030
‫ここでは､ ピストルをポインターにしています｡

60
00:04:58,300 --> 00:05:07,960
‫さて､ 仮想メソッドを持たない場合､ C++はデフォルトでポインタの型（これはガンポインタ）を使用することになります｡

61
00:05:07,960 --> 00:05:11,890
‫その型を使って､ 呼び出すメソッドを探すことを覚えておいてください｡

62
00:05:11,890 --> 00:05:18,130
‫そのため､ pistolでオーバーライドされたメソッドではなく､ 先頭のこのshootメソッドを呼びに行きます｡

63
00:05:18,130 --> 00:05:25,630
‫pistolのオーバーライドされたメソッドを呼び出すためには､ pistol型のポインタを持っていなければならない｡

64
00:05:25,960 --> 00:05:27,520
‫今はそれでいい｡

65
00:05:27,520 --> 00:05:29,350
‫そして､ なぜそうするのか､ その理由がわかるはずです｡

66
00:05:29,350 --> 00:05:30,430
‫それは､ 効率のためです｡

67
00:05:30,430 --> 00:05:32,410
‫C++は効率が命です｡

68
00:05:32,410 --> 00:05:40,600
‫もし､ コンパイル時や実行時にコストがかかるようなことがあれば､ C++は､ あなたが要求しない限り､ デフォルトではそうしないでしょう｡

69
00:05:40,630 --> 00:05:47,620
‫C++では､ 「これは銃のポインターだから､ この銃のポインターのメソッドを呼び出そう」とルックアップするのはとても簡単なことなのです｡

70
00:05:47,620 --> 00:05:50,080
‫そこで登場するのがDynamic Dispatchです｡

71
00:05:50,080 --> 00:05:54,070
‫この派手な言葉は､ 基本的に「そんなことはさせない」という意味です｡

72
00:05:54,070 --> 00:05:59,950
‫そこで､ 「ちょっと待てよ､ あの銃のポインターには何が入っているんだ？

73
00:05:59,950 --> 00:06:02,140
‫そこでリアルタイプとは？

74
00:06:02,380 --> 00:06:06,250
‫そして､ 私たちが実感する本当のタイプは､ タイプピストルなのです｡

75
00:06:06,250 --> 00:06:12,520
‫そして､ その型のメソッドがオーバーライドされているかどうか､ 自問自答する必要があります｡

76
00:06:12,520 --> 00:06:13,600
‫そして､ そう､ あるんです｡

77
00:06:13,600 --> 00:06:26,110
‫では､ どうすればC++にほんの少し効率の悪いことを許可して､ ポインタの型を変更せずに上書きできるようにできるでしょうか｡

78
00:06:26,110 --> 00:06:32,470
‫実際､ 独自のカスタムアクタークラスを持っている場合のように､ 多くの場合､ これは不可能です｡

79
00:06:32,590 --> 00:06:38,290
‫Unreal には､ 新しいクラスを導入するたびにエンジン全体を変更する必要があるような､ 特定のアクト

80
00:06:38,290 --> 00:06:41,290
‫クラスを指すポインタが設定されていません｡

81
00:06:41,290 --> 00:06:43,120
‫いや､ それは無理な話だ｡

82
00:06:43,120 --> 00:06:46,360
‫俳優の星のようなものへのポインタを持っている｡

83
00:06:46,360 --> 00:06:51,010
‫つまり､ begin playが呼ばれたら､ あなたのbegin playメソッドを呼び出すようにしたいのです｡

84
00:06:51,010 --> 00:06:52,630
‫だから､ バーチャルでなければならないのです｡

85
00:06:52,630 --> 00:06:54,340
‫そして､ ここが重要なポイントです｡

86
00:06:54,340 --> 00:07:02,500
‫親クラスのメソッドの前にvirtualを付けると､ これはC++に「ちょっと待て､ 銃ポインタ型のポインタに対してshootを呼び出す場合､

87
00:07:02,500 --> 00:07:14,350
‫これが例えばピストルでないこと､ このshootメソッドがオーバーライドされていることを確認する必要がある」と合図することになる｡

88
00:07:14,350 --> 00:07:19,390
‫そこで､ 今､ runを押すと､ bangとpillが表示されるのがわかると思います｡

89
00:07:19,420 --> 00:07:24,070
‫つまり､ Dynamic Dispatchの期待通りに動いているわけです｡

90
00:07:24,070 --> 00:07:33,430
‫そして､ これは基本的に､ これが本当にポインタに保持されているのはどんな型なのかをチェックして､ 関連するメソッドを呼び出すことを意味する用語である｡

91
00:07:33,940 --> 00:07:40,450
‫さて､ よく目にする構文として､ overrideというキーワードがあります｡

92
00:07:40,450 --> 00:07:45,520
‫そして､ それをvirtualとしてオーバーライドしようとしているメソッドの後に置くのです｡

93
00:07:45,790 --> 00:07:53,680
‫そして､ 基本的にoverrideキーワードは厳密には必要ありませんし､ また､ 銃の子クラスの何かに対してvirtual

94
00:07:53,680 --> 00:07:56,200
‫againを置くこともありません｡

95
00:07:56,200 --> 00:07:59,350
‫だから､ バーチャルを入れる必要はないけれど､ やっても損はない｡

96
00:07:59,560 --> 00:08:07,030
‫しかし､ オーバーライドは､ 命名が正しいかどうかを確認することができるので､ 特に便利です｡

97
00:08:07,030 --> 00:08:10,690
‫だから､ 実行を押すと､ オーバーライドしているときは､ すべて以前と同じように実行されるのです｡

98
00:08:10,690 --> 00:08:17,290
‫しかし､ このメソッドの名前を間違えてしまったので､ オーバーライドを行わないとします｡

99
00:08:17,290 --> 00:08:19,490
‫そして､ 私はそれを撮影禁止としたのです｡

100
00:08:19,870 --> 00:08:22,750
‫例えば､ 名前を間違えてコピーしていたとか｡

101
00:08:22,750 --> 00:08:24,520
‫コピーではなく､ 打ち込みました｡

102
00:08:24,520 --> 00:08:29,230
‫今､ runを押すと､ ほら､ また同じエラーが出ましたね､ shootを呼び出そうとしているからです｡

103
00:08:29,230 --> 00:08:32,350
‫間違って上書きしてしまいました｡

104
00:08:32,350 --> 00:08:33,820
‫バンバン鳴るんですよ｡

105
00:08:33,910 --> 00:08:37,840
‫そこで､ これを回避する方法として､ 「何かをオーバーライドしたいんです」と言うことがあります｡

106
00:08:37,840 --> 00:08:44,170
‫ここでoverrideキーワードを入れてコンパイルしてみると､ shooterはoverrideとマークされていますが､

107
00:08:44,170 --> 00:08:52,360
‫オーバーライドするためのメソッドや仮想メソッドはありません｡

108
00:08:52,360 --> 00:08:57,340
‫そこで､ 私のコードを修正し､ 撮影に戻るようにするだけです｡

109
00:08:57,340 --> 00:08:59,320
‫そして今､ 私の意図したとおりに動作しています｡

110
00:08:59,320 --> 00:09:04,150
‫そのため､ オーバーライドを置くことで安全性を高め､ 瞬時にこれを実現することができるのです｡

111
00:09:04,240 --> 00:09:09,170
‫また､ オーバーライドしようとしているものが仮想でない場合にも対応できます｡

112
00:09:09,190 --> 00:09:19,410
‫そうすると､ オーバーライドと表示されているのがわかると思いますが､ その親クラスにはシュート用の仮想関数がないのでオーバーライドされないのです｡

113
00:09:19,420 --> 00:09:25,570
‫これで､ C++がどのように仮想関数を使用し､ 実装しているか､ また､ なぜ仮想関数を明示しなければならないかについて､

114
00:09:25,570 --> 00:09:28,330
‫ある程度理解していただけたと思います｡

115
00:09:28,600 --> 00:09:32,890
‫では､ 一般的な仮想関数の使用例について､ もう少し考えてみましょう｡

116
00:09:32,890 --> 00:09:34,750
‫すでにエンジンからいくつか見えています｡

117
00:09:34,750 --> 00:09:37,630
‫バーチャルが使われているのを見たことがあるのはどこですか？

118
00:09:38,450 --> 00:09:40,190
‫どのような場面で使うことを想定していますか？

119
00:09:40,220 --> 00:09:46,880
‫先ほど､ 銃の使用例を見てきましたが､ 銃のオーバーライドによって､ さまざまな方法で射撃ができるようになります｡

120
00:09:47,300 --> 00:09:55,530
‫この2つの質問に対する答えを考えたときに､ 親クラスの機能をオーバーライドする仮想関数を使うことを､ 他にどのように想像しましたか？

121
00:09:55,550 --> 00:10:01,290
‫この講義のディスカッションのリンクを辿って行き､ そこで答えを投稿してください｡

122
00:10:01,310 --> 00:10:06,010
‫使用例や今まで使ったことのある場所､ 他の人が思いついたことを見ることができます｡

123
00:10:06,020 --> 00:10:11,250
‫そうすることで､ バーチャル・メソッドの理解を固めることができるかもしれませんね｡

124
00:10:11,270 --> 00:10:12,280
‫今回の講義は以上です｡

125
00:10:12,290 --> 00:10:15,710
‫次回は､ バーチャルメソッドを怒涛のように使っていくところでお会いしましょう｡

