I am reading the following source code (taken from this repository).
void AVariableReplicationCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// Variable A doesn't have any additional replication condition
DOREPLIFETIME(AVariableReplicationCharacter, A);
// Variable B should only replicate to the owner of this actor
DOREPLIFETIME_CONDITION(AVariableReplicationCharacter, B, COND_OwnerOnly);
}
The function is implemented in .cpp
but it has not corresponding declaration in .h
. Surprisingly it can be compiled.
I attempted to replicate it with a simpler one as follows but it does not compile.
#include <iostream>
using namespace std;
class Parent
{
public:
virtual void Job() const;
};
void Parent::Job() const
{
cout << "Parent" << endl;
}
class Child : public Parent
{
public:
virtual void Job() const override;
};
void Child::Job() const
{
Parent::Job();
cout << "Child" << endl;
}
class GrandChild : public Child
{
};
//= ATTEMPTING TO IMPLEMENT WITHOUT DECLARATION
void GrandChild::Job() const
{
Child::Job();
}
int main()
{
std::cout << "Hello World!\n";
std::getchar();
}
Question
What C concept am I missing here?
CodePudding user response:
The function is implemented in .cpp but it has not corresponding declaration in .h.
A declaration for the member function must be there inside the class definition in one form or another.
Most likely, here the macro is used to indirectly write the declaration for the concerned member function. In any case, to be able to define a member function outside the class, a corresponding declaration for that particular member function must be there inside the class. Whether that declaration comes from macro is irrelevant.
CodePudding user response:
There is already an accepted answer to this question, but it's vague and based on guessing, so I'll try to give a more definitive answer:
When declaring a class that can be replicated, it has to be defined as either an AActor
or a UActorComponent
. Both of which use the UCLASS()
macro to denote that the following class declaration needs to be integrated into Unreals reflection using the Unreal Header Tool (UHT) which runs before the actual build and generates code. This code is written into a generated header file called "foo.generated.h" and code file called "foo.gen.cpp" where "foo" stands for your header filename (without extension). The header is always the last include in your header and exists once per header file, not per class.
Inside of the class, you also have to call the GENERATED_BODY()
macro (or alternatively the GENERATED_UCLASS_BODY()
macro, but I believe that's legacy stuff). That's where the code goes that's generated for the class itself by the UHT. It contains information about the UPROPERTY()
and UFUNCTION()
declarations and, if you are using the reflection on the class, also declares an override of GetLifetimeReplicatedProps()
that you then have to implement.
This is not the only method that is declared by the UHT. If you are using RPCs, you also have to create an implementation to something you did not actually declare. A method declared as Foo()
will have Foo_Implementation()
as a body (because the implementation of the actual Foo()
will be created via UHT, calling your implementation at some point) and optionally even a Foo_Validate()
.
You can read more about this here.
Regarding the UHT, Unreals docs are very vague, but I encourage you to look into its code on their GitHub. Also, you can actually "go to declaration" of GetLifetimeReplicatedProps()
after doing a compile. You should be able to view the generated code in the headers, they are located in the "Intermediate/Build" folders of your project.