What does the Cast<Atank>(GetPawn()) mean?

hello,i have a method called GetControlledTank() which is implemented like this:

Atank*  ATankPlayerController::GetControlledTank(){


return Cast<ATank>(GetPawn());

} why must we use the word Cast? can’t we simply return GetPawn()?.
thanks in advance.

I think it is because getpawn() is part of the controller class and you want to cast it to a specific type of pawn not just an apawn

To treat it as a different type because we want to call functions off of ATank

Example in standard C++
https://godbolt.org/z/2t9CrH

we are in Tank.cpp and if we use GetPawn() only it should return the same type of object i still don’t understand about the usage of Cast<>() here.can you please explain a little more ?

That’s irrelevant. You could define ATankPlayerController::GetControlledTank in TankPlayerController.cpp if you really wanted to.

That’s not how return works.

ATank* ATankPlayerController::GetControlledTank() const

This is what what defines the return type, specifically ATank*. GetPawn() returns a APawn* which is not ATank* but it can be safely cast down because ATank is a APawn the pawn that is returned is a ATank. The reason we want to cast down is because we want to call functions off of ATank. See the above godbolt link.

oh you mean the thing that it returns isn’t a type of Atank* and even if we try to access Atank functions with just returning GetPawn() it would produce error and what cast does here is it converts that returned Pawn to ATank object ?
and can we just do this method to convert pawns types to each other ?
why in that godbolt link the that dynamic-Cast isn’t forking on object of class A ?

Yes

Yes though I saw on GitHub that a pull request was accepted for 4.24 for a templated version of GetPawn so instead of Cast<T>(GetPawn()) you can do GetPawn<T>()

Because the cast failed. The first call was passed in an object of type A which is not a B. Also I just realised I messed up my previous explaination.

although you said yes,i think you meant we can convert only between parent and derived classes sometimes it can be mutual and most of the times its a one way right ?

Sorry I thought that’s what you were saying. Though if you’re strictly talking about polymorphism/inheritance then yes. Because

int x = 2.3;

is an implicit cast from double to int.

I believe what you’re asking is about upcasting/downcasting. Given the hierarchy:

AActor
|- APawn
 |- ACharacter

Casting from ACharacter to APawn is an upcast whereas the other way around APawn to ACharacter is a downcast. Upcasts are always safe to do ACharacter is APawn however the other way round might not be - which is why there’s an if statement in the example as it can and does fail in one instance.
If you have a variable that is of type APawn*, it may or may not actually be ACharacter.

e.g. With our ATankPlayerController it will always be controlling an ATank so it’s a safe assumption to make and personally I wouldn’t bother checking if the cast failed. (This is not true for ATankAIController later on).

ok thx for your explanation.just casting from ACharacter to APawn, you mean we convert APawn to ACharacter ? or the other way around ?(sorry this ambiguity is cuz of my bad english ). and can you expand this a little bit more please its also for the same reason that i don’t fully understand it.

Other way around. In the linked example there was an implicit cast from B* to A* in the function call.

then i don’t know why u are saying its safe.can you tell me what do you mean by that ?

It should always succeed.

void Test(const A* X)
{
    X->Foo();
    //X->Bar(); // does not compile
    auto Y = dynamic_cast<const B*>(X);
    if (Y)
    {
        Y->Bar();
    }
}


int main()
{
    A a;
    B b;
    Test(&a);
    Test(&b);
}

In the last line in main there’s an implicit upcast to A*, I don’t need to check if it failed or not whereas I should check the downcast in Test because it can fail and does fail with the first call to Test with a

so here is my understanding of what you said:

auto Y=dynamic_cast<const B*><X>;./// when X is an object of A;

this one is called down-cast which is not succesfull always.

auto Y=dynamic_cast<const B*><X>;./// when X is an object of B;

this one is called upcast which is always succesfull.
actually both types are the same here so i don’t think we call it upcast.but if we had const A* in <> it would be a upcast.

am i right ?

No that line is a downcast in both cases because X is const A* as denoted by the parameter.

Test(&b);

This is the upcast, it’s implicit. The compiler is actually doing this for you.

Test(static_cast<const A*>(&b));

i see.GetPawn() from what i see in ue4 documentation APawn* GetPawn() const.it returns a pointer of Apawn and we are calling this :Cast<ATank>(GetPawn());; since ATank is derived from APawn, so its a downcast but why we are simply returning it ? i mean why don’t we need to check if its nullptr or not like we did in this example.

Because it’s not being dereferenced here. Also as I said before since this player controller only controls tanks it’s a relatively safe assumption that the cast will never fail.

i still cannot get it if it’s a downcast it means its not always safe to do it and it may fail.

Remove B from the equation so the last line of main i.e. if you just have this

void Test(const A* X)
{
    X->Foo();
    auto Y = dynamic_cast<const B*>(X);
    if (Y)
    {
        Y->Bar();
    }
}


int main()
{
    A a;
    Test(&a);
}

The explicit cast in Test fails because it is not of type B in this situation and so you avoid dereferencing a null pointer

i know it all in normal c++ i just don’t get it in

Cast<ATank>(GetPawn()); 

ATank here is a Character and its a derived class of APawn.here we are trying the same thing you just expressed a DownCast but why is it always successful then ?