描述: 创建和表示分离, 统一创建过程可以有不同的表示
UE4中NewObject的创建过程就是典型的创建者模式, 而且这种模式在编程中是最常用到的.
在了解NewObject之前, 先看看我写的这两篇文章:
在NewObject创建流程:
随便选择一个NewObject作为入口:
template< class T >
FUNCTION_NON_NULL_RETURN_START
T* NewObject(UObject* Outer = (UObject*)GetTransientPackage())
FUNCTION_NON_NULL_RETURN_END
{
// Name is always None for this case
FObjectInitializer::AssertIfInConstructor(Outer, TEXT("NewObject with empty name can't be used to create default subobjects (inside of UObject derived class constructor) as it produces inconsistent object names. Use ObjectInitializer.CreateDefaultSuobject<> instead."));
return static_cast<T*>(StaticConstructObject_Internal(T::StaticClass(), Outer, NAME_None, RF_NoFlags, EInternalObjectFlags::None, nullptr, false, nullptr));
}
UObject* StaticConstructObject_Internal
(
UClass* InClass,
UObject* InOuter /*=GetTransientPackage()*/,
FName InName /*=NAME_None*/,
EObjectFlags InFlags /*=0*/,
EInternalObjectFlags InternalSetFlags /*=0*/,
UObject* InTemplate /*=NULL*/,
bool bCopyTransientsFromClassDefaults /*=false*/,
FObjectInstancingGraph* InInstanceGraph /*=NULL*/,
bool bAssumeTemplateIsArchetype /*=false*/
)
{
LLM_SCOPE(ELLMTag::UObject);
SCOPE_CYCLE_COUNTER(STAT_ConstructObject);
UObject* Result = NULL;
#if WITH_EDITORONLY_DATA
UE_CLOG(GIsSavingPackage && InOuter != GetTransientPackage(), LogUObjectGlobals, Fatal, TEXT("Illegal call to StaticConstructObject() while serializing object data! (Object will not be saved!)"));
#endif
checkf(!InTemplate || InTemplate->IsA(InClass) || (InFlags & RF_ClassDefaultObject), TEXT("StaticConstructObject %s is not an instance of class %s and it is not a CDO."), *GetFullNameSafe(InTemplate), *GetFullNameSafe(InClass)); // template must be an instance of the class we are creating, except CDOs
// Subobjects are always created in the constructor, no need to re-create them unless their archetype != CDO or they're blueprint generated.
// If the existing subobject is to be re-used it can't have BeginDestroy called on it so we need to pass this information to StaticAllocateObject.
const bool bIsNativeClass = InClass->HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic);
const bool bIsNativeFromCDO = bIsNativeClass &&
(
!InTemplate ||
(InName != NAME_None && (bAssumeTemplateIsArchetype || InTemplate == UObject::GetArchetypeFromRequiredInfo(InClass, InOuter, InName, InFlags)))
);
#if WITH_HOT_RELOAD
// Do not recycle subobjects when performing hot-reload as they may contain old property values.
const bool bCanRecycleSubobjects = bIsNativeFromCDO && !GIsHotReload;
#else
const bool bCanRecycleSubobjects = bIsNativeFromCDO;
#endif
bool bRecycledSubobject = false;
Result = StaticAllocateObject(InClass, InOuter, InName, InFlags, InternalSetFlags, bCanRecycleSubobjects, &bRecycledSubobject);
check(Result != NULL);
// Don't call the constructor on recycled subobjects, they haven't been destroyed.
if (!bRecycledSubobject)
{
FScopeCycleCounterUObject ConstructorScope(InClass, GET_STATID(STAT_ConstructObject));
(*InClass->ClassConstructor)( FObjectInitializer(Result, InTemplate, bCopyTransientsFromClassDefaults, true, InInstanceGraph) );
}
if( GIsEditor && GUndo && (InFlags & RF_Transactional) && !(InFlags & RF_NeedLoad) && !InClass->IsChildOf(UField::StaticClass()) )
{
// Set RF_PendingKill and update the undo buffer so an undo operation will set RF_PendingKill on the newly constructed object.
Result->MarkPendingKill();
SaveToTransactionBuffer(Result, false);
Result->ClearPendingKill();
}
return Result;
}
上面一段代码展示了UObject的创建流程:
(1) StaticAllocateObject(获取Object的内存地址)
(2) (*InClass->ClassConstructor)(...) (调用构造函数)
(3) Result->MarkPendingKill();
(4) SaveToTransactionBuffer(Result, false);
(5) Result->ClearPendingKill()
正好和创建者模式描述一致: 传入不同的创建目标(UClass), 同样的创建流程, 创建出不同的UObject.
网友评论