通知
すべてクリア
05/02/2024 12:00 am
クラスを継承する事の意味は親クラスの処理を子クラスが全部引き継ぐとの事です。なので基本的にすべての子クラスは親クラスの処理をベースにもっています。(子クラスで特別にオーバーライドしなかった関数はそのまま親の関数と同じ処理を行います。)
そしてすべての子クラスは親クラスとして宣言ができます。
例えば
APickupが親クラス
ABatteryPickupが子クラス
だと
APickup* a = Cast<APickup>(ABatteryPickup);は可能です。(親の機能をすべて持っているので、すべてのAPickupの関数を使える)
ですが逆に
ABatteryPickup* b = Cast<ABatteryPickup>(APickup)は不可能です。
親クラスは子クラスのすべての関数を持っているわけではないからです。
完璧に正しい理由ではありませんが、理解しやすくするための話です。
05/02/2024 12:00 am
回答ありがとうございます。
Battery Collector⑦のTestPickup->WasCollected()、およびBattery Collector⑧の「親のWasCollected」は、
のどちらが呼ばれているのでしょうか?私は
APickup::WasCollected_Implementation()
or ABatteryPickup::WasCollected_Implementation()
のどちらが呼ばれているのでしょうか?私は
APickup::WasCollected_Implementation()
が呼ばれると思っています。実際にはバッテリーがDestory()しているのでABatteryPickup::WasCollected_Implementation()
が呼ばれており、私の認識は間違っているのですが、どこで認識がズレているのか分からないので教えてもらえればと思っています。~~~親の機能をすべて持っているので、すべてのAPickupの関数を使える
のですが、親と子の持つ両方が同じ関数を持つ場合、どちらの処理が呼ばれるのか知りたいです。ここでの質問は、子(
ABatteryPickup
)がWasCollected()
を呼んだらAPickup::WasCollected_Implementation()
or ABatteryPickup::WasCollected_Implementation()
のどちらが呼ばれるかという質問ではないです。- Battery Collector⑦のTestPickupは
APickup
でキャストしたオブジェクトなのに、なぜABatteryPickup::WasCollected_Implementation()
が呼ばれるのか。 - Battery Collector⑧では「親のWasCollected」を実行しているのに、なぜ
ABatteryPickup::WasCollected_Implementation()
が呼ばれるのか。(特に子のWasCollectedはBPで上書きしているので、C++側に書いたDestory()の処理は呼ばれないのではないかと思っています)
これらが知りたいです。
05/02/2024 12:01 am
BatteryCollector⑧の「親のWasCollected」の部分はどの部分を示しているのかよくわからないため、⑦の部分だけで説明します。
APickup* const TestPickup = Cast<APickup>(CollectedActors[isCollected]);
この処理でCollectedActorsはAActorのポインターの配列です。
その中でisCollected番目のAActorのポインターをAPickupとしてキャストをしています。
ここでCollectedActorsはAActorの配列ですが、ここにはAActorの子クラスであれば何でも与えを入れる事が可能です。
ABatteryPickupも含めてそうです。CollectedActors[isCollected]は何らかのポインターを情報として持っていて、キャストを使って
このポインターの中の与えがAPickupクラスで変換できるのかをチェックし、TestPickupとして保存します。
このTestPickupをAPickupとして宣言しているので、TestPickupに与えがあったら(APickupに変換できるのであれば)APickupの関数を使う事ができます。
ただし、この流れの中で別にCollectedActors[isCollected]に保存されている情報が変わったりしないので
実際入っているのはABatteryPickupのポインターってことになりますね。
なのでTestPickup->WasCollected()はTestPickupのポインターが示しているABatteryPickupのWasCollected関数が呼ばれることになります。
その中でisCollected番目のAActorのポインターをAPickupとしてキャストをしています。
ここでCollectedActorsはAActorの配列ですが、ここにはAActorの子クラスであれば何でも与えを入れる事が可能です。
ABatteryPickupも含めてそうです。CollectedActors[isCollected]は何らかのポインターを情報として持っていて、キャストを使って
このポインターの中の与えがAPickupクラスで変換できるのかをチェックし、TestPickupとして保存します。
このTestPickupをAPickupとして宣言しているので、TestPickupに与えがあったら(APickupに変換できるのであれば)APickupの関数を使う事ができます。
ただし、この流れの中で別にCollectedActors[isCollected]に保存されている情報が変わったりしないので
実際入っているのはABatteryPickupのポインターってことになりますね。
なのでTestPickup->WasCollected()はTestPickupのポインターが示しているABatteryPickupのWasCollected関数が呼ばれることになります。
親と子の持つ両方が同じ関数を持つ場合、どちらの処理が呼ばれるのか知りたいです。
基本的にただ名前が同じ関数を作成するとエラーになります。
同じ関数を宣言するためにはオーバーライドの宣言が必要です。
そしてどちらの処理が呼ばれるのかは上の説明からつながる部分ですが、親クラスの関数が呼び出されたら親クラスの処理が呼ばれて、子クラスの関数が呼ばれたら子クラスの処理が呼ばれます。
キャストしたクラスが重要ではなく、データー自体が重要です。じゃ、なんで親クラスでキャストするのかって言われると
拾う物の種類が増えるとした場合、
親クラス:APickup
子クラス:ABattery, ABanana, AApple
このように仮定します。
拾ったものがBatteryなのかBananaなのかAppleなのかわからない時、いちいちすべてのクラスにキャストするのではなく、共通の処理を持っている
親クラスにキャストしてみて、その親クラスで定義した共通関数を呼び出すためです。
同じ関数を宣言するためにはオーバーライドの宣言が必要です。
そしてどちらの処理が呼ばれるのかは上の説明からつながる部分ですが、親クラスの関数が呼び出されたら親クラスの処理が呼ばれて、子クラスの関数が呼ばれたら子クラスの処理が呼ばれます。
キャストしたクラスが重要ではなく、データー自体が重要です。じゃ、なんで親クラスでキャストするのかって言われると
拾う物の種類が増えるとした場合、
親クラス:APickup
子クラス:ABattery, ABanana, AApple
このように仮定します。
拾ったものがBatteryなのかBananaなのかAppleなのかわからない時、いちいちすべてのクラスにキャストするのではなく、共通の処理を持っている
親クラスにキャストしてみて、その親クラスで定義した共通関数を呼び出すためです。
05/02/2024 12:02 am
変数の宣言の際ポインターとして宣言しているため、値渡しではなく参照渡しです。Castで形が変わってもそれが伝えた与えを変える処理ではないのでポインターは同じです。
スクショを見て頂くとわかりやすいと思いますが、
AControllerで宣言されている変数をAPlayerControllerにキャストしたときその両方の変数を見てみたらそのポインターの与えは同じだってことを確認できます。
スクショを見て頂くとわかりやすいと思いますが、
AControllerで宣言されている変数をAPlayerControllerにキャストしたときその両方の変数を見てみたらそのポインターの与えは同じだってことを確認できます。
「親のWasCollected」の部分
この処理は関数をオーバーライドをする際に親の関数の処理を呼ぶ処理です。
子クラスのWasCollectedが実行される際に親のWasCollectedにノードが進行するとその親クラスのWasCollectedを実行する意味です。
子クラスのWasCollectedが実行される際に親のWasCollectedにノードが進行するとその親クラスのWasCollectedを実行する意味です。
05/02/2024 12:03 am
回答ありがとうございます。
ポインタのキャストはC言語特有の特殊な話のようですね。求めていた情報に辿り着くことができました。~~~
「親のWasCollected」の部分
ここで言う親とはAPickupのことでしょうか?であれば、
にはDestory()が無いのでバッテリーが消えることと矛盾しないでしょうか?
APickup::WasCollected_Implementation()
にはDestory()が無いのでバッテリーが消えることと矛盾しないでしょうか?
05/02/2024 12:04 am
ここで言っている親は「BatteryPickup」です。ブループリントの右上に書かれております。
なのでAPickup::WasCollected_Implementation()にDestroy()は書かれておりませんが、ABatteryPickup::WasCollected_Implementation()にDestroy()が書かれていますので、
ちゃんと削除されるようになっています。
処理順番は以下になります。
なのでAPickup::WasCollected_Implementation()にDestroy()は書かれておりませんが、ABatteryPickup::WasCollected_Implementation()にDestroy()が書かれていますので、
ちゃんと削除されるようになっています。
処理順番は以下になります。
ブループリント「BatteryPickup_BP」::WasCollectedイベント ( エフェクトの生成 親:WasCollected = ABatteryPickup::WasCollected_Implementation ( Super::WasCollected_Implementation = APickup::WasCollected_Implementation ( ログの出力 ) Destroy() ) )
05/02/2024 12:04 am
回答ありがとうございます。
「親」と聞くと継承元のクラスを想像しますが、ここではオーバライド元の関数のことを指すようですね。