Quick C++ Question - How do i check if the class of an object is == to a certain class

At the moment i have

if (inputLocationX_Override->IsA() )

The class im trying to see if it is is “AHC_EditorLogic_VectorData” but when i place it into the IsA() function, it doesnt like it. I seen in a different thread that you need to put “YourClass::StaticClass()” into it but im unsure of what this means in my case.

Im very new to C++.

Thanks :slight_smile: <3

If you already have the class and want to test for an exact match you can simply == it to another class.

You can call ::StaticClass() to get a class.

If you want to know if one class is a child class of another, you can use IsA but it is more common to use a Cast on object instances:

APawn* SomePawn = Cast<APawn>(SomeActor);
if (IsValid(SomePawn)) {
 // SomeActor is a valid pawn (or deriving from pawn)!
}
else {
  // SomeActor is invalid or not a pawn at all
}
2 Likes

I’m not sure if that code example is valid for me. I have my reference “inputLocationX_Override” and id like to find out if it is the class “AHC_EditorLogic_VectorData”. This class is not the class that i’m running the code in.

I also tried this

if (inputLocationX_Override->IsA(AHC_EditorLogic_VectorData::StaticClass()))

but it wasnt having any of it.

Its also very possible that im just not understanding your code example xD

Can you post the entire code and any error you are getting?

so this is inside a function.

HC_EditorLogic_OPE.h

UFUNCTION(BlueprintPure)
	double value_LocationX();

HC_EditorLogic_OPE.cpp

double AHC_EditorLogic_OPE::value_LocationX()
{
	if (!inputLocationX_Override) {
		return inputLocationX;
	}
	else {
		if (inputLocationX_Override->IsA(AHC_EditorLogic_VectorData::StaticClass())) {
			TArray<double> functionArray = inputLocationX_Override->value_VectorValue();
			if (!functionArray[0]) {
				return 0;
			}
			else {
				return functionArray[0];
			}
		}
		return inputLocationX_Override->value_FloatValue();
	}
}

full header file

#pragma once

#include "CoreMinimal.h"
#include "EditorLogic/HC_EditorLogic_Event_Base.h"
#include "HC_EditorLogic_Data_Base.h"
#include "EditorObject/HC_LevelEditorObject_Base.h"
#include "HC_EditorLogic_OPE.generated.h"

/**
 * 
 */
UCLASS()
class HC_LEVELEDITOR_API AHC_EditorLogic_OPE : public AHC_EditorLogic_Event_Base
{
	GENERATED_BODY()

public:


	/*
	* Modify Location
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	bool bModifyLocation = true;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	class AHC_EditorLogic_Data_Base* modifyLocation_Override;

	UFUNCTION(BlueprintPure)
	bool value_ModifyLocation();

	/*
	* Local Location (Position)
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	bool bLocalLocation = true;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	class AHC_EditorLogic_Data_Base* localLocation_Override;

	UFUNCTION(BlueprintPure)
	bool value_LocalLocation();

	/*
	* Location inputs, Override and Output function
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	double inputLocationX = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	double inputLocationY = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	double inputLocationZ = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	class AHC_EditorLogic_Data_Base* inputLocationX_Override;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	class AHC_EditorLogic_Data_Base* inputLocationY_Override;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Position")
	class AHC_EditorLogic_Data_Base* inputLocationZ_Override;

	UFUNCTION(BlueprintPure)
	double value_LocationX();

	UFUNCTION(BlueprintPure)
	double value_LocationY();

	UFUNCTION(BlueprintPure)
	double value_LocationZ();

	/*
	* Modify Rotation
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	bool bModifyRotation = true;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	class AHC_EditorLogic_Data_Base* modifyRotation_Override;

	UFUNCTION(BlueprintPure)
	bool value_ModifyRotation();

	/*
	* Local Rotation
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	bool bLocalRotation = true;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	class AHC_EditorLogic_Data_Base* localRotation_Override;

	UFUNCTION(BlueprintPure)
	bool value_LocalRotation();

	/*
	* Rotation inputs, Override and Output function
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	double inputRotationX = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	double inputRotationY = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	double inputRotationZ = 0;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	class AHC_EditorLogic_Data_Base* inputRotationX_Override;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	class AHC_EditorLogic_Data_Base* inputRotationY_Override;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Rotation")
	class AHC_EditorLogic_Data_Base* inputRotationZ_Override;

	UFUNCTION(BlueprintPure)
	double value_RotationX();

	UFUNCTION(BlueprintPure)
	double value_RotationY();

	UFUNCTION(BlueprintPure)
	double value_RotationZ();

	/*
	* Array of target objects
	*/
	UPROPERTY(BlueprintReadWrite, EditAnywhere)
	TArray<AHC_LevelEditorObject_Base*> targetObjects;





	//Override triggered function
	void logicEventTriggered() override;
	

};

full cpp file

#include "EditorLogic/HC_EditorLogic_OPE.h"


double AHC_EditorLogic_OPE::value_LocationX()
{
	if (!inputLocationX_Override) {
		return inputLocationX;
	}
	else {
		if (inputLocationX_Override->IsA(AHC_EditorLogic_VectorData::StaticClass())) {
			TArray<double> functionArray = inputLocationX_Override->value_VectorValue();
			if (!functionArray[0]) {
				return 0;
			}
			else {
				return functionArray[0];
			}
		}
		return inputLocationX_Override->value_FloatValue();
	}
}

double AHC_EditorLogic_OPE::value_LocationY()
{
	if (!inputLocationY_Override) {
		return inputLocationY;
	}
	else {
		if (inputLocationY_Override->IsA()) {
			TArray<double> functionArray = inputLocationY_Override->value_VectorValue();
			if (!functionArray[1]) {
				return 0;
			}
			else {
				return functionArray[1];
			}
		}
		return inputLocationY_Override->value_FloatValue();
	}
}

double AHC_EditorLogic_OPE::value_LocationZ()
{
	if (!inputLocationZ_Override) {
		return inputLocationZ;
	}
	else {
		if (inputLocationZ_Override->IsA()) {
			TArray<double> functionArray = inputLocationZ_Override->value_VectorValue();
			if (!functionArray[2]) {
				return 0;
			}
			else {
				return functionArray[2];
			}
		}
		return inputLocationZ_Override->value_FloatValue();
	}
}

double AHC_EditorLogic_OPE::value_RotationX()
{
	if (!inputRotationX_Override) {
		return inputRotationX;
	}
	else {
		if (inputRotationX_Override->IsA()) {
			TArray<double> functionArray = inputRotationX_Override->value_VectorValue();
			if (!functionArray[0]) {
				return 0;
			}
			else {
				return functionArray[0];
			}
		}
		return inputRotationX_Override->value_FloatValue();
	}
}

double AHC_EditorLogic_OPE::value_RotationY()
{
	if (!inputRotationY_Override) {
		return inputRotationY;
	}
	else {
		if (inputRotationY_Override->IsA()) {
			TArray<double> functionArray = inputRotationY_Override->value_VectorValue();
			if (!functionArray[1]) {
				return 0;
			}
			else {
				return functionArray[1];
			}
		}
		return inputRotationY_Override->value_FloatValue();
	}
}

double AHC_EditorLogic_OPE::value_RotationZ()
{
	if (!inputRotationZ_Override) {
		return inputRotationZ;
	}
	else {
		if (inputRotationZ_Override->IsA()) {
			TArray<double> functionArray = inputRotationZ_Override->value_VectorValue();
			if (!functionArray[2]) {
				return 0;
			}
			else {
				return functionArray[2];
			}
		}
		return inputRotationZ_Override->value_FloatValue();
	}
}

bool AHC_EditorLogic_OPE::value_ModifyLocation()
{
	if (!modifyLocation_Override) {
		return bModifyLocation;
	}
	else {
		return bool(modifyLocation_Override->value_FloatValue());
	}
}

bool AHC_EditorLogic_OPE::value_LocalLocation()
{
	if (!localLocation_Override) {
		return bLocalLocation;
	}
	else {
		return bool(localLocation_Override->value_FloatValue());
	}
}

bool AHC_EditorLogic_OPE::value_ModifyRotation()
{
	if (!modifyRotation_Override) {
		return bModifyRotation;
	}
	else {
		return bool(modifyRotation_Override->value_FloatValue());
	}
}

bool AHC_EditorLogic_OPE::value_LocalRotation()
{
	if (!localRotation_Override) {
		return bLocalRotation;
	}
	else {
		return bool(localRotation_Override->value_FloatValue());
	}
}

void AHC_EditorLogic_OPE::logicEventTriggered()
{
	//Checks if target is valid or if logic state set to false
	uint8 len = targetObjects.Num();
	if (len == 0 || value_LogicState() == false) {
		callPassthrough();
		return;
	}
	

	//Sets location and rotation for all selected actors
	for (int i = 0; i < len; i++) {

		if (value_ModifyLocation()) {
			if (value_LocalLocation()) {
				targetObjects[i]->SetActorLocation(FVector(targetObjects[i]->transform_Default.GetTranslation().X + value_LocationX(),
					targetObjects[i]->transform_Default.GetTranslation().Y + value_LocationY(),
					targetObjects[i]->transform_Default.GetTranslation().Z + value_LocationZ()));
			}
			else {
				targetObjects[i]->SetActorLocation(FVector(value_LocationX(), value_LocationY(), value_LocationZ()));
			}
			
		}

		if (value_ModifyRotation()) {
			if (value_LocalRotation()) {
				targetObjects[i]->SetActorRelativeRotation(FRotator(value_RotationX(), value_RotationY(), value_RotationZ()));
			}
			else {
				targetObjects[i]->SetActorRotation(FRotator(value_RotationX(), value_RotationY(), value_RotationZ()));
			}
		}
	}

	//Call passthrough function
	callPassthrough();

}

So to hopefully more clearly present what im trying to do:

the variable “inputLocationX_Override” can hold class “AHC_EditorLogic_Data_Base”.

the class “AHC_EditorLogic_Data_Base” then splits into 2 sub classes “AHC_EditorLogic_FloatData_Base” and “AHC_EditorLogic_VectorData” and then from there, multiple classes are made from these two.

What im trying to do is determins if the class inside of “inputLocationX_Override” inherits from either “AHC_EditorLogic_FloatData_Base” or “AHC_EditorLogic_VectorData” .

Edit: i just included the header file for HC_EditorLogic_VectorData and now i have no error in this code:

double AHC_EditorLogic_OPE::value_LocationX()
{
	if (!inputLocationX_Override) {
		return inputLocationX;
	}
	else {
		if (inputLocationX_Override->IsA(AHC_EditorLogic_VectorData::StaticClass())) {
			TArray<double> functionArray = inputLocationX_Override->value_VectorValue();
			if (!functionArray[0]) {
				return 0;
			}
			else {
				return functionArray[0];
			}
		}
		return inputLocationX_Override->value_FloatValue();
	}
}

This could potentially be fixed

1 Like

You still haven’t posted the actual error message. You’ve just said “having none of it,” which can mean many things.

My guess is that it’s complaining that AHC_EditorLogic_VectorData is not a defined class at this point in your source file. If that is the case, then you need to add an #include "HC_EditorLogic_VectorData.h" below the other includes at the top of your C++ file.

Also, there’s a few things in the code that could be cleaned up.

		if (!functionArray[0]) {
			return 0;
		}
		else {
			return functionArray[0];
		}

If functionArray[0] is 0, return 0, else return functionArray[0].
You can replace all that with just a single return functionArray[0];

Separately – switching on the specific class is almost always a clue that you’re missing something in the design.
Why wouldn’t you simply make value_FloatValue() be virtual in whatever class inputLocationX_Override is a pointer to, and implement it to return the appropriate functionArray[0] value in that implementation?

I believe it was indeed me just missing the include. I added it to the header file and not the cpp file though and it seemed to work. Is there a reason to ever add a header file to the cpp file over the header file?

For the cleanup, I was under the impression !functionArray[0] would check if it was a valid entry in the array, and then if it wasn’t, id simply return a 0 instead. I assumed simply putting return functionArray[0] would crash if it happened to not exist. is this incorrect?

Also, on your final comment, value_FloatValue() returns a float and value_VectorValue() returns an array. They are both functions from a single class, but that class splits into 2 different classes, one for float values and one for vectors. some override functions require either a float or a vector, but in this particular case i wanted it to allow for both to be allowed to i need to check which class the value is coming from to determine if that class is outputting a float or a vector. Hopefully i understood what you meant by that final point. xD

Also keep in mind this only works for things derived from UObject. That whole class reflection system simply doesn’t exist otherwise and at that point you have to use normal C++ like, dynamic_cast, etc…

Yes, compile times can be affected. Also it can help clarify where dependencies lie for someone scanning your code.

Your code is “correct” but it takes many lines to do what a single line would do.
If the value is 0, you return 0. Else you return the value.
So, consider: what would the code return if you just return the value, and it happens to be 0?
0 is the only non-valid value for the ! operator.

Regarding C++ include files, they are a special kind of challenge we get with C++ code. The main reason they matter, is compile times: You want to re-compile as little as possible when you change some particular thing, and anything including a header, will recompile when that header is changed.
You should almost never add additional includes to the header files.
The reason is that, when you change the now-included class, or any of its dependencies, then anyone who includes the now-including class, ALSO need to be recompiled. This very quickly spirals into “change anything, recompile everything.”
An include in a CPP file generally means that only those files who actually use the class in question, need re-compiling when that header changes.
(There’s something called “Unity Build” that slightly changes this, but not worth worrying about in this context.)

If you need to declare a pointer to some class, you can forward declare it with class AMyWhateverClass; and reference it in the header, as long as you only actually use it (dereference it) in the CPP file that includes the real header.