Both are usually used for downcasting (from a base to a derived class); upcasting is always safe, so doesn't need an explicit cast. As noted in the comments, both are equivalent (and equivalent to an implicit conversion) if you use them for upcasting.
For downcasting, static_cast
is faster but potentially dangerous, since it doesn't perform a runtime check and gives undefined behaviour if the conversion is not valid. It also works with non-polymorphic types, while dynamic_cast
requires the run-time type information that's only available from polymorphic types.
Your introductory book should cover this in detail.