仮想関数まわり、NativeEvent関数のオーバーライドについて
miyahuji111.hatenablog.com
NativeEvent、ImplementableEventについては上記を参考
通常のvirtual付き関数と、NativeEvent指定した関数の継承時の振る舞いについてまとめる
準備
AActor継承の適当なクラスを作成する、このクラスに適当に関数を適当に用意し、継承先のクラスで云々やってみる
標準の仮想関数について
virtual指定子をつけたりつけなかったりのやつを確認
UCLASS() class ATestClass_A : public AActor { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "TEST") FString A() { return TEXT("Called A() in TestClass_A"); } UFUNCTION(BlueprintCallable, Category = "TEST") virtual FString B() { return TEXT("Called B() in TESTClass_A"); } }; UCLASS() class ATestClass_B : public ATestClass_A { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "TEST") FString A() { return TEXT("Called A() in TestClass_B"); } UFUNCTION(BlueprintCallable, Category = "TEST") virtual FString B() override { return TEXT("Called B() in TESTClass_B"); } };
A()はオーバーロードでB()はオーバーライド、コンパイルしたらエディタでATestClass_A、ATestClass_Bオブジェクトをそれぞれ作成し、ATestClass_AのポインタとしてそれぞれのA()、B()を実行してみる
はい
まとめ
- C++の範囲内で収まるなら普通のvirtual指定子が普通な挙動する
- BPエディタで実装の上書きはできない
純粋仮想関数
- とりあえず後で
NativeEventのオーバーライド
本題、C++内でもオーバーライドしたいし、エディタでも処理を書きたい、書きたくない…?
/* コンパイル不可 */ UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "TEST") virtual FString A();
- NativeEventを指定した関数にvirtual指定子があるとコンパイルエラー
- virtualなしのオーバーロードなら通る、エディタでも問題なく動くけれど、もちろんオーバーロードの挙動にしかならない
正しいやり方はこれ
// .h UCLASS() class ATestClass_A : public AActor { GENERATED_BODY() public: UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "TEST") FString A(); virtual FString A_Implementation(); }; UCLASS() class ATestClass_B : public ATestClass_A { GENERATED_BODY() public: UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "TEST") FString A(); virtual FString A_Implementation() override; }; // .cpp FString ATestClass_A::A_Implementation() { return TEXT("in ATestClass_A"); } FString ATestClass_B::A_Implementation() { return TEXT("in ATestClass_B"); }
_Implemetation()をvirtual付きで宣言して、そちらをオーバーライドする、これだとBPエディタで更にオーバーライドも出来る、全クリ
How to overide BlueprintNativeEvent method from base class? - UE4 AnswerHub
おまけ: ImplementableEventを急に継承先でつける
/* コンパイル可 */ UCLASS() class ATestClass_A : public AActor { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "TEST") FString A() { return TEXT("in ATestClass_A"); } }; UCLASS() class ATestClass_B : public ATestClass_A { GENERATED_BODY() public: UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "TEST") FString A(); };
/* コンパイル不可 */ UCLASS() class ATestClass_A : public AActor { GENERATED_BODY() public: UFUNCTION(BlueprintCallable, Category = "TEST") virtual FString A() { return TEXT("in ATestClass_A"); } }; UCLASS() class ATestClass_B : public ATestClass_A { GENERATED_BODY() public: UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "TEST") virtual FString A() override; };
なんかオーバーロードだとコンパイルが通る、しかしエディタでこの関数ををオーバーライドしようとしてみると
だめそう
まとめ
- ImplementableEventは素直につかおう