What does "class" mean before parameter?

1.2k views Asked by At

Unreal Engine generates following function:

void AFlyingPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    //stuff...
}

Notice the "class" specifier before the parameter's type. What does it mean?

3

There are 3 answers

0
Fritz On BEST ANSWER

How Unreal works

As you might know, Unreal manages multiple implementations of the same base classes to define a common ground. Every developer must, then, create child classes from the ones the engine has to offer in order to perform tasks within the Engine.

In this case, it's about an InputComponent, which is used to handle User Input, interpret it and pass it along to Controllers and/or, subsequently, Pawns.

For example, if you want to define elements such as Pawns, PlayerControllers, AIControllers, the HUD and the like, you do so in a GameMode you then configure into the Project Settings or, directly, into the level through the World Settings (in case your level needs a specific GameMode). Those references are classes as well, which will be instantiated by the Engine in due time to setup the Game.

Here comes the pitfall

With this in mind, here comes the downside. In UE4 C++ (yeah, it's a thing!), since the engine ties the loose ends, sometimes you won't be able to use certain classes because they're not declared. Of course, you can include them but think about it: how many circular dependencies will be created if you make all the inclusions you need for one class only to find another one might indirectly require that one?

The solution is Forward Declaration. This case, however, is a special flavor called Shorthand Forward Declaration in which you declare a type in the exact place where you use the class.

This is extremely handy if you're just using it once, so you don't end up with a terrible list of declarations at the start of your file.

Bringing this to the real world

For example, should you want to know the current default Pawn class defined, you can check the GetDefaultPawnClass public variable in your GameMode (Let's call it MyGameMode). The variable is defined as follows:

TSubclassOf < APawn > DefaultPawnClass

See that TSubclassOf? That's actually a Class Template to ensure type safety. It's actually a hint to the Editor to show you only classes derived from APawn.

Should you use a custom type and based in what I've been discussing so far, you could find stuff like this:

TSubclassOf<class ASpeedyPawn> MySpeedyPawn;
2
leslie.yao On

1. The 1st possibility, this might be a forward declarations, if UInputComponent is not declared before. So

void AFlyingPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent)

forward declares a class named UInputComponent, and the parameter InputComponent is of type UInputComponent*.

Note that a new class name may also be introduced by an elaborated type specifier which appears as part of another declaration, but only if name lookup can't find a previously declared class with the same name.

class U;
namespace ns{
    class Y f(class T p); // declares function ns::f and declares ns::T and ns::Y
    class U f(); // U refers to ::U
    Y* p; T* q; // can use pointers and references to T and Y
}

2. The 2nd possibility, the keyword class might be used for disambiguation.

If a function or a variable exists in scope with the name identical to the name of a class type, class can be prepended to the name for disambiguation, resulting in an elaborated type specifier

e.g.

int UInputComponent;
class UInputComponent { /* ... */ };

// without the class keyword it won't compile because the name UInputComponent is ambiguous
void AFlyingPawn::SetupPlayerInputComponent(class UInputComponent* InputComponent) 

3. The 3rd possibility, it might not mean anything.

If UInputComponent has been declared as class, then using the keyword class or not doesn't change anything. Note that if the type previously declared doesn't match then compilation would fail.

1
Noel Widmer On

Usually the class keyword is used to declare a new class type. But not in this scenario.

This is called a Forward Declaration.
These are used when a type you want to use is not known. F.e. Imagine two header files. Each of them using the type of the other. That is a circular dependency and is not allowed. But you still need to use the others type in each file, right?

What you can do is to forward declare the type in one file, you can then get rid of the include. Getting rid of the include solves the circular dependency and makes you loose all the information of the type (available members f.e.), but you can use the type itself. This also saves you a lot of "space" because the compiler doesn't have to include the other header.

I don't want to say too much because there is already a great answer on SO:
When can I use a forward declaration?

What that post doesn't cover very well is why you would want to do a forward declaration. As I said, it solves circular dependencies and saves you from including the type. Including a file means to let the compiler copy the file's contents to where the include is. But you don't always need to know the file's content. If you can get away with only using the features described in the post I linked you can save the include. This in turn will reduce the size of the compilers output.