zoukankan      html  css  js  c++  java
  • UE4里CPP的用法笔记

    本篇文章纯属笔记,记录UE4里CPP的一些用法、区别、原理和最佳实践等。(持续更新中)

    .generated.h

    当声明的类型需要反射(需要UCLASS(), USTRUCT()等等)时,需要在头文件包含这个文件,UHT在分析头文件内容的时候会生成相应的反射代码。

    MODULENAME_API

    这个声明在class后的宏是负责由UBT分析,然后生成DLL的时候,将当前模块的类导出给其他模块使用,如果你明确不需要导出给其他模块使用,那么不需要这个宏。

    类的前缀

    前缀A,意味着这个类从AActor继承下来,意味着这是个可以直接在world里spawn出来的东西。
    前缀U,意味着这个类从UObject继承下来,不能直接在world里spawn,必须从属于某个Actor。

    GENERATED_BODY() vs GENERATED_UCLASS_BODY()

    后者是比较旧的版本引擎才使用的,现在一般不论是UCLASS还是USTRUCT都推荐使用前者。还有一个区别,前者是不自动包含public的,所有在下面的成员都是private,所以一般都会先在开头写上宏,然后后面立马加上public。

    构造函数的选择

    UClass的类构造函数有两种选择,最基本的和带参数的:(二选一)

    UMyObject::UMyObject() {}
    UMyObject::UMyObject(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {}
    

    那么我们怎么知道改使用哪个呢?一是先看基类是怎么选择的,比如有一些类不推荐你用不带参数的构造函数:

    /** Initialization constructor. */
    TOctree(const FVector& InOrigin,float InExtent);
    
    /** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */
    TOctree();
    

    二是看需求,比如基类在构造函数里面创建了一些组件,但是你不需要这些组件或者你想用其他组件替换之,那么使用带参的构造函数:

    AUDKEmitterPool::AUDKEmitterPool(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer.DoNotCreateDefaultSubobject(TEXT("SomeComponent")).DoNotCreateDefaultSubobject(TEXT("SomeOtherComponent")))
    {}
    AMyAIController::AMyAIController(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer.SetDefaultSubobjectClass<UMyPathFollowingComponent>(TEXT("PathFollowingComponent")))
    {}
    

    另外还有一个小细节,构造函数一般直接写在对应的cpp文件里就好了,header里不需要声明。如果你非要在header里写构造函数,那么需要UCLASS加宏:UCLASS(CustomConstructor),来告诉UHT不用自动生成的构造函数。

    UHT无视.h文件里的宏

    不要在头文件里这样用宏:

    #if WITH_EDITOR
        UFUNCTION(BlueprintCallable)
        void K2_Foo();
    #endif
    

    UHT会无视掉 WITH_EDITOR 宏,并且在.h相应的.generated.h反射文件里声明所有的函数。
    这是有道理的,因为在蓝图或者Lua开发中,开发者一般会直接使用所有在Editor里可以看到的函数,如果UHT允许 WITH_EDITOR 宏产生作用,那么在其他平台(比如DSLinux)编译的时候会直接挂了。

    编写只在编辑器生效的 UPROPERTY()

    推荐写法:

    #if WITH_EDITORONLY_DATA
    	UPROPERTY()
    	USkeletalMeshComponent* PreviewMesh;
    #endif
    

    另外要注意不能在蓝图里尝试使用这个 UPROPERTY() ,否则在正式打包之后一定会找不到这个变量。

    meta里不能有多余的分隔符

    无论是在写 UFUNCTION 宏还是 UCLASS 宏,在 meta = (xxx,xxx) 里不能在最后一个宏后面写多余的逗号,比如错误的用法 meta = (DeprecatedFunction, DeprecationMessage="Message Text", )。

    如果在子类覆盖父类在构造函数中实例化的组件

    比如你自己继承AAIController写了自己的AMyAIController,你想在这个类里使用自己写的UMyPathFollowingComponent,一个比较麻烦的点是AAIController在构造函数里实例化了原生的寻路组件。

    AAIController::AAIController(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer)
    {
    	bSetControlRotationFromPawnOrientation = true;
    	PathFollowingComponent = CreateDefaultSubobject<UPathFollowingComponent>(TEXT("PathFollowingComponent"));
    }
    

    替换掉寻路组件需要这样干:(注意一下,组件名字必须一样是父类写的"PathFollowingComponent")

    AMyAIController::AMyAIController(const FObjectInitializer& ObjectInitializer)
    	: Super(ObjectInitializer.SetDefaultSubobjectClass<UMyPathFollowingComponent>(TEXT("PathFollowingComponent"))
    {
    }
    
  • 相关阅读:
    给你一个网站你是如何来渗透测试的
    web漏洞扫描工具集合
    成都Uber优步司机奖励政策(3月16日)
    北京Uber优步司机奖励政策(3月16日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(3月16日)
    成都Uber优步司机奖励政策(3月15日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(3月15日)
    北京Uber优步司机奖励政策(3月15日)
    优步UBER司机全国各地奖励政策汇总 (3月14日-3月20日)
    成都Uber优步司机奖励政策(3月14日)
  • 原文地址:https://www.cnblogs.com/trav/p/13485208.html
Copyright © 2011-2022 走看看