Why does calling my override fire the parent function instead?

To verify for myself how overriding functions in structs work, I built a super-simple test case:

USTRUCT(BlueprintType)
struct FTestBase {
	GENERATED_BODY()    
		virtual void TestFunc() {
		GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Base function");
		}
};

USTRUCT(BlueprintType)
struct FTestChild : public FTestBase {
	GENERATED_BODY()    
		void TestFunc() override {
		GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Red, "Child function");
		}    
};

Having finished that I made a generic holding array of type FTestBase, added both a base and a child struct to it, and called TestFunc() for both, expecting to get one of each debug message:

TArray<FTestBase> testArr;
FTestBase base;
FTestChild child;
testArr.Add(base);
testArr.Add(child);
for (int i = 0; i < testArr.Num(); i++) {
	testArr[i].TestFunc();
}

When this executes, however, the override in FTestChild never runs; I get two “Base function” messages every single time. Am I doing something wrong here, or is it not possible to use function overrides the way I’m attempting?

What you trying to do works only with pointers. Hmm it gonna be kind hard to explain if you dont know how CPU and memory works

CPU don’t distinguish varable types… it does not destines variables at all, all it have is memory addresses, compiler generates code patterns for CPU to make it read specific types and when you declare type of inform compiler which pattern use for it to generate code for CPU and if it’s not a pointer (memoery address), most importently it informs how much memory need to be allocated for specific varable. So lets say parent structure have varable A, B, C and child adds D and E, in momory child would look like this (1 letter is a byte)

AAAABBCCCDDDDDDEE

where parent look like this:

AAAABBCCC

and if you set child type to parent type, CPU cant place D and E in parent, it does not have memory allocated for D and E and the way memory reading code works it would start reading D as A (specially in array where valuables are placed in memory in order one by one and code reads them by memory address offset) because it thinks it parent type. So D and E will be removed, as child is compatible with parent compiler acknowledge that it can do so, but you will lose data and child permanently becames parent. Try it for your self set child to parent and then parent to child varable, you will see you lose data on child extra variables because of it.

Pointer on other hand points to specific place in memory, they latterly memory addresses placed in memory it self that points somewhere, you can figure that type of pointer informs compiler how to read data from that memory address. Things is if you cahnge type of pointer from child to parent it is still memory address pointing to same place in memoery, but it does not change data it self in that address, it will stay as it is as it was allocated in first place, so if you cast it back to child you will be able to read data that there is.

In short, if you use non-pointer varables you change type pernamently, when pointer varbales change of type can be reverted (as data it self is not changed) as you only changing way how data is read from address in pointer not data it self. If you pernamently change type of varable compiler cant use override function on it will fall it back to parent function.

It’s kind of hard for me to explain better sorry i hope you understand it ^^’

Sadly UE4 reflection system and blueprints don’t support structure pointers, but C++ it self can, and blueprint functions can use any C++ trickery it can do, so you can implement blueprint support for it somehow. Also keep in mind UE4 don’t memory manage anything that reflection system does not support, you would need to manually memory manage with new and delete keywords, if you allocated varable with new and lose pointer to it without using “delete” you will have memory leak, dead data that is not controllable anymore and it will be there as long as process will continue running