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 ?
This is what what defines the return type, specifically ATank*. GetPawn() returns a APawn* which is notATank* but it can be safely cast down because ATankis aAPawn 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 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 ACharacterisAPawn 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.
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
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.
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 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 ?