Grand unified C++/blueprint cast interface explanation
This post is an attempt to ask and answer some questions about using interfaces in c++ and blueprint that collects together answers from other places. The goal is to not only point out how to do things but why. I found that once I understood the why it was much easier to understand what was going on and what I should do.
TL;DR: If you want to mix C++ and Blueprint your best bet is probably to follow something like Rama's tutorial and then use the Execute_* functions in C++. This is because UE4's Blueprint uses a message passing implementation of interfaces which is not what most C++ programmers are used to with classes.
Disclaimer: I am just figuring this out as well so some of the following may be wrong (which is why it is a question!). Feel free to answer and correct my many misunderstandings. Hopefully once we're done we will have a clear and detailed explanation of how to uses classes and interfaces in C++ and Blueprint.
Question 1: How do I use interfaces in C++ and blueprint? Answer 1: See various tutorials such as
The last one above was the one that gave me the final piece of the puzzle for my work.
Question 2: Why is all of this so complicated?
The short answer is because C++ allows multiple inheritance (which can be used to simulate interfaces) but not true interfaces while Blueprint allows interfaces but not multiple inheritance.
The long answer involves understanding the key difference between Blueprint and C++. Your C++ code sees the core UE4 C++ code via headers and so it can reference and call all of the UE4 C++ functions. Anything implemented in Blueprint has no C++ header files and so you can't directly reference Blueprint created things from C++.
Let me repeat that last sentence because it took me a long time to understand the implications yet once I did everything made much more sense: Anything implemented in Blueprint has no C++ header files and so you can't directly reference Blueprint created things from C++.
If you think about it Blueprint cannot be generating C++ headers and compiling them on the fly. If it did, you couldn't have the quick and easy workflow you get in Blueprint because you would sometimes have to quit and restart the engine just like you do when changing C++ headers. Thus Blueprint extends the C++ classes (either the core UE4 classes or your own C++ classes) but does not generate new C++ headers.
So the only way you can call Blueprint code from C++ is by doing one of the following:
Let me expand on what I think is going on in 2 above because it confused me for a long time. Imagine you have a Bar class defined in Blueprint which inherits from AActor and implements the IFooInterface and you are given an AActor*SomeActor in C++ which you know points to a Bar object. If you want to call the DoSomethign method of the IFooInterface you naturally want to do something like:
IFooInterface* MyFoo = Cast(SomeActor);
This will fail. This confused me for a very long time. It fails because a the Bar class in Blueprint DOES NOT INHERIT FROM IFooInterface. Yes it implements the same functions as IFooInterface but because UE4 didn't know about your IFooInterface class when it was compiled, their AActor cannot inherit from IFooInterface and so the Bar defined in Blueprint inherits from AActor (because Blueprint does not allow multiple inheritance). Even if you try
IFooInterface* MyFoo = (IFooInterface*) SomeActor;
things will fail for the same reason. Fundamentally SomeActor does not inherit from IFooInterface even though it implements the same methods.
The solution is basically message passing. UE4 uses the GENERATED_IINTERFACE_BODY() macro which you call in the IFooInterface definition to add the Execute_* methods as static methods of your class. What Execute_DoSomething does is basically send a message to a UObject and says "Please see if you claim to implement the methods in IFooInterface and if so call the DoSomething method." This is kind of like how classes work in languages like python or Objective C or Smalltalk but not how classes generally work in C++ (which is why I found everything so confusing).
Once again TL;DR: If you want to mix C++ and Blueprint your best bet is probably to follow something like Rama's tutorial and then use the Execute_* functions in C++. This is because UE4's Blueprint uses a message passing implementation of interfaces which is not what most C++ programmers are used to with classes. If you try to use Cast or InterfaceCast things may not work as you expect.
To Epic: did I understand this correctly or can you correct me where I am wrong?
asked Apr 18 '15 at 06:53 PM in C++ Programming
I wanted to comment on a few parts of your post for clarification:
This is both accurate and the best practice to use. Defining base behavior in code and overriding that behavior in a blueprint based off of your code allows for easy communication between code and blueprints.
This is a bit confusing to read. Foo* MyItem points to Foo and allows you to call the Bar method associated with the specific MyItem. MyItem->Baz will fail because Baz doesn't exist in code.
If you create an interface in code there are two ways to implement it in blueprints. If the blueprint is based on a custom class, you can use multiple inheritance to inherit the interface into the code class. The other option is to open the class defaults of the blueprint and add the interface directly to the blueprint. In both cases, you can access the functions inside the interface from the blueprint. As for being passed an UObject* or AActor*, this would likely be based on what interface function you're using and if it requires an object or actor as input.
This is correct. Basically when you attempt to cast it will follow the "is a" relationship of inheritance. Using the line of code above, it is basically saying "if SomeActor "is a" (inherits from) IFooInterface, then set it to MyFoo". Since neither SomeActor nor Bar actually inherit from the interface the cast will fail.
answered Mar 09 '16 at 08:26 PM
Follow this question
Once you sign in you will be able to subscribe for any updates here