UE4 C++ Getters for objects have issues with blueprints?

Here my class. It’s an actor component that I am attaching to an object. This is the .h file:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "HealthSubsystem.h"
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "SurvivalSystemComponent.generated.h"


UCLASS(ClassGroup=SurvivalSystemComponents, meta=(BlueprintSpawnableComponent), Blueprintable)
class CUSTOMTPC_API USurvivalSystemComponent : public UActorComponent
{
	GENERATED_BODY()

private:
	///<summary>
	/// Health subsystem
	///</summary>
	UPROPERTY(EditAnywhere, Category = "Survival subsystems")
		UHealthSubsystem* Health;

public:	
	// Sets default values for this component's properties
	USurvivalSystemComponent();
	 
	//This is a pointer -> to a -> [constant UHealthSusbsytem]
	UFUNCTION(BlueprintCallable, Category = "Survival subsystem methods")
		UHealthSubsystem const* GetHealthSubsystem() const;

	 
protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

};

Ok and here is the .cpp file

// Fill out your copyright notice in the Description page of Project Settings.

#include "SurvivalSystemComponent.h"
#include "EngineMinimal.h"

#define DISPLAY_MESSAGE(message) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT(message));} 

// Sets default values for this component's properties
USurvivalSystemComponent::USurvivalSystemComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
	// ...
}




UHealthSubsystem const* USurvivalSystemComponent::GetHealthSubsystem() const
{
	return Health;
}

// Called when the game starts
void USurvivalSystemComponent::BeginPlay()
{
	Super::BeginPlay();

	if (Health == nullptr) 
	{
		Health = NewObject<UHealthSubsystem>();
		Health->Initialize(100,100, 0, 0, true);
	}
}

// Called every frame
void USurvivalSystemComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction); 

	if (Health != nullptr)
	{
		Health->SetDepletionRate(DeltaTime * 0.05f * 100);
		Health->DepleteHealth();
	}		
}

Focus on the UHealthSubsystem object called Health. Also focus on the method GetHealthSubsystem();

The intent of that getter method is to return a pointer to a constant UHealthSubsystem. That means that you cannot use setter methods if you were to call GetHealthSubsystem. The syntax on where I put the const modifier keyword is based off the clockwise/spiral rule. Essentially you need to read it backwards, that is:

UHealthSubsystem const* GetHealthSubsystem() const;
[Note, the const at the end of course means that this method shouldn’t be modifying the class.]

This statement, if you read it right to left says “pointer to a constant UHealthSubsystem”.

So if I call GetHealthSubsystem().SomeSetterMethod(someValue), it shouldn’t work. I am mutating the object itself.

This is my intent. I also want to make it so that blueprints can read this object. If i didn’t put the UFUNCTION macro, everything complies. However, if i left it there, I get this compile error :
“Cannot convert from const UHealthSubsystem* to UHealthSubsystem*”.
“Conversion loses qualifiers”
“Cannot convert from const UHealthSubsystem* to UHealthSubsystem*”.
“Conversion loses qualifiers”

Why is this happening? Why does the compiler not understand that I am only going to return a immutable UHealthSubsystem pointer, who’s object that it is pointing to cannot be modified (although of course, the pointer itself can point to a different object).

Also, if I put the const keyword AFTER the “*” symbol, it compiles fine. Of course, why would I even be using this? This is saying that I can mutate the object but I can’t change where it points to.

And YES, UHealthSubsystem is a UObject. In fact, it inherits from a class called BaseSystem which is what inherits UObject.

Another note: It tell’s me the error comes from line 14 on the .h file. 0_0.

Here’s the error messages :

Info Compiling game modules for hot reload
Info Parsing headers for CustomTPCEditor
Info   Running UnrealHeaderTool "F:\Projects\Unreal Projects\CustomTPC\CustomTPC.uproject" "F:\Projects\Unreal Projects\CustomTPC\Intermediate\Build\Win64\CustomTPCEditor\Development\CustomTPCEditor.uhtmanifest" -LogCmds="loginit warning, logexit warning, logdatabase error" -Unattended -WarningsAsErrors -installed
Info Reflection code generated for CustomTPCEditor in 3.9255561 seconds
Info Performing 4 actions (4 in parallel)
Info CustomTPC.generated.cpp
Info SurvivalSystemComponent.cpp
Error F:\Projects\Unreal Projects\CustomTPC\Source\CustomTPC\Public\SurvivalSystem\SurvivalSystemComponent.h(14) : error C2440: '=': cannot convert from 'const UHealthSubsystem *' to 'UHealthSubsystem *'
Error F:\Projects\Unreal Projects\CustomTPC\Source\CustomTPC\Public\SurvivalSystem\SurvivalSystemComponent.h(14) : note: Conversion loses qualifiers
Error F:\Projects\Unreal Projects\CustomTPC\Source\CustomTPC\Public/SurvivalSystem/SurvivalSystemComponent.h(14) : error C2440: '=': cannot convert from 'const UHealthSubsystem *' to 'UHealthSubsystem *'
Error F:\Projects\Unreal Projects\CustomTPC\Source\CustomTPC\Public/SurvivalSystem/SurvivalSystemComponent.h(14) : note: Conversion loses qualifiers
Info ERROR: UBT ERROR: Failed to produce item: F:\Projects\Unreal Projects\CustomTPC\Binaries\Win64\UE4Editor-CustomTPC-668.dll
Info Total build time: 9.21 seconds (Local executor: 0.00 seconds)

Well, this is not const:
UPROPERTY(EditAnywhere, Category = “Survival subsystems”)
UHealthSubsystem* Health;

That is why it fails to compile. It has nothing to do with Blueprints, it is a problem with your C++ code.

HTH

If I did that, then I can’t call the mutator methods from my cpp file, such as Initialize(), and SetDepletionRate(). I commented those methods out anyways. I changed the :

UPROPERTY(EditAnywhere, Category = “Survival subsystems”) UHealthSubsystem* Health;

to

UPROPERTY(EditAnywhere, Category = “Survival subsystems”) UHealthSubsystem const* Health;

and I actually still get the same compiler errors as up top. However, if I take out both the UPROPERTY and UFUNCTION macros, it compiles

bump

Try returning a non const object, but instead return a singleton pointer to the object. You can return a const pointer to a static pointer that can only be set once.