プリプロセッサディレクティブ
プリプロセッサは、ソースコードをコンパイラーに渡す前に実行される前処理です。
プリプロセッサ ディレクティブ | C言語
pragma once
通常、とあるヘッダーファイルを他の複数のファイルで include すると、それぞれのファイルでヘッダーファイルの内容が複数回展開され、同じ定義が複数見つかる事で重複定義エラーを引き起こす。
それを事前に防ぐするために使用されるのが「#pragma once」である。
ヘッダーファイルに「#pragma once」と記述すると、そのヘッダーファイルが 1 度だけインクルードされるようにコンパイラに指示する事が出来る。
B.h と C.h で「#include “A.h” 」と書く場合、A.h に「#pragma once」と記述すると A.h が複数回展開されなくなる。
(「#pragma once」は C++ 標準の機能ではなく、特定のコンパイラのみがサポートしている機能)
pragma region
以下のように記述する事でソースコード内の任意の範囲を折り畳む事が出来る。
#pragma region {表示名}
//メンバ変数など
#pragma endregion
依存関係の解決
include
主に他のヘッダーファイルを現在のファイルに読み込み、その場所に展開するために使用する。
#include "{フォルダ名}/{ファイル名}.h"
using
名前空間や型の別名の定義
「using {別名} = {型名};」と記述する事で名前空間や型の別名を定義する事が出来る。
以下のコードでは FString クラスを「str」という別名で使用できるようにしている。
using str = FString;//別名を定義
void ASampleActor::Hoge()
{
str Message = TEXT("Hello World");
UE_LOG(LogTemp, Log, TEXT("%s"), *Message);
}
名前空間名の省略
本来なら「{名前空間名}::{関数名}()」と記述しなくてはいけない場合でも「using namespace {名前空間名};」を追加する事で「{関数名}()」のみの記述でもエラーを吐かなくなるが、その名前空間に宣言されている変数や関数と同じ名前のものがスコープ内に存在する場合は注意が必要。
#pragma once
namespace SampleNamespace
{
void SampleFunction()
{
}
}
#include "SampleNamespace.h"// using のみではなく include も必要
using namespace SampleNamespace;// using で名前空間をインポート
void ASampleActor::Hoge()
{
//本来なら「SampleNamespace::SampleFunction()」と記述しないとエラーを吐くが、using を使用する事で関数名のみの記述でもエラーを吐かなくなる
SampleFunction();
}
前方宣言
外部のクラスのポインタや参照を使用する際、そのクラスの詳細(メンバ)を知る必要が無い場合に使用する。
include とは異なり、ヘッダーファイルを読み込む訳ではないためコンパイル時間を減らしたり、循環参照を避けたりする事が出来る。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SampleActor.generated.h"
//「#include "Camera/CameraComponent.h"」と記述してもエラーを吐かないようにする事は出来るが、依存性が強くなったり、コンパイル時間が長くなったりする恐れがある
class UCameraComponent;
UCLASS()
class SAMPLE_API ASampleActor : public AActor
{
GENERATED_BODY()
private:
UCameraComponent* CameraComponent;
};
マクロ
UPROPERTY
ガベージコレクションとの関係
アクセス権(全体)
プロパティ指定子 | レベルエディタでの閲覧 | レベルエディタでの編集 | ブループリントエディタ等での閲覧 | ブループリントエディタ等での編集 |
---|---|---|---|---|
EditAnywhere | 可 | 可 | 可 | 可 |
VisibleAnywhere | 可 | 不可 | 可 | 不可 |
EditDefaultsOnly | 不可 | 不可 | 可 | 可 |
VisibleDefaultsOnly | 不可 | 不可 | 可 | 不可 |
EditInstanceOnly | 可 | 可 | 不可 | 不可 |
VisibleInstanceOnly | 可 | 不可 | 不可 | 不可 |
アクセス権(ブループリント)
「BlueprintReadWrite」ではブループリントから Get も Set も出来るが、
「BlueprintReadOnly」では Get しか出来なくなる。
private なメンバ変数に対するアクセス権
通常、private なメンバ変数に対して「BlueprintReadWrite」等を付けると「BlueprintReadWrite should not be used on private members」というエラーが発生する。
しかし、以下のように「AllowPrivateAccess」を true に設定する事でエラーが無くなり、ブループリントからでも private なメンバ変数にアクセス出来るようになる。
private:
UPROPERTY(BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))//「BlueprintReadWrite」のみではエラーが発生する
int32 Num;
「AllowPrivateAccess」を true に設定した private なメンバ変数に他の C++ クラスからアクセスしようとすると「’ASampleActor::Num’: cannot access private member declared in class ‘ASampleActor’」といったエラーが発生するが、他のクラスが C++ ではなくてブループリントの場合はアクセス出来てしまう。
TitleProperty
構造体を配列などで使用する際に以下のように記述する事で、構造体の特定のメンバの値を配列の要素のタイトルにする事が出来る。
#pragma once
#include "CoreMinimal.h"
#include "SampleStruct.generated.h"
USTRUCT(BlueprintType)
struct FSampleStruct
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
FString Name;
UPROPERTY(EditAnywhere)
int32 Num;
};
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "SampleStruct.h"
#include "SampleActor.generated.h"
UCLASS()
class SAMPLE_API ASampleActor : public AActor
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, meta = (TitleProperty = "Name"))// TitleProperty には構造体のメンバの名前を設定する
TArray<FSampleStruct> SampleStructs;
};
この例では FSampleStruct 構造体の Name という名前のメンバを配列の要素のタイトルに使用。
FString 型以外にも float 型なども配列の要素のタイトルに使用できる。
正しくないメンバの名前を「TitleProperty」に設定した場合は「Invalid Title Property!」と表示される。
キーワード
関数に対する static と const
static 関数
「UFUNCTION(BlueprintPure)」を付けた static 関数は下画像のような見た目になり、その関数を宣言しているクラスのインスタンスが無くても使用できる。
(クラスのインスタンスに依存しない)
UFUNCTION(BlueprintPure)//当然、BlueprintCallable 等でも OK
static bool StaticFunction();//前方に static を付ける
const メンバ関数
一方、関数名の後ろに const を付けた const メンバ関数は「UFUNCTION(BlueprintCallable)」であってもピュア関数のような見た目になるが、その関数を宣言しているクラスのインスタンスを Target に接続しないとコンパイルエラーが発生する。
(クラスのインスタンスに依存する)
UFUNCTION(BlueprintCallable)
bool ConstFunction() const;//後方に const を付ける
static 関数と const メンバ関数の違い
static 関数ではそのクラスの静的ではないメンバを読み取ろうとしたり、書き込もうとするとコンパイルエラーが発生するが、const メンバ関数ではそのクラスの静的ではないメンバを読み取る事が出来る。
// static 関数
bool ASampleActor::StaticFunction()
{
// static 関数はそのクラスの静的ではないメンバを参照できないため、コンパイルエラーが発生する
return MemberVariable;
}
// const メンバ関数
bool ASampleActor::ConstFunction() const
{
//クラスの静的ではないメンバを読み取る事は出来るが、書き込む事は出来ない
//MemberVariable = true;
// static 関数ではないためコンパイルエラーは発生しない
return MemberVariable;
}
inline
template
最後に
参考記事
プリプロセッサディレクティブ
依存関係の解決
マクロ
- UPROPERTY
- UE5/UE4 C++で変数のアクセス権系の属性をプロパティ指定子(Property Specifiers)で指定する(UPROPERTY(EditAnywhere)、UPROPERTY(EditDefaultsOnly)、UPROPERTY(EditInstanceOnly)、UPROPERTY(VisibleAnywhere)、UPROPERTY(VisibleDefaultsOnly)、UPROPERTY(VisibleInstanceOnly))
- UE4 よく使うUPROPERTYメモ
- [UE5]UE初心者がよく使っているUPROPERTY、UFUNCTIONまとめ
- [UE5]便利そうなUPROPERTYまとめ
- UObjectの動作原理