Static Cast
static_cast doesn't do any run time checking of the types involved, which means that unless you know what you are doing, they could be very unsafe. It also only allows casting between related types, such as pointers or references between Base and Derived, or between fundamental types, such as long to int or int to float.
It does not allow casts between fundamentally different types, such as a cast between a BaseA and BaseB if they are not related. This will result in a compile time error.
Dynamic Cast
dynamic_cast will do run time checking as well, and if the instance cannot be cast into another derived type, it will return a null pointer.
Examples
If we have the following classes
class B {};
class D : B {};
then you can do the following
B* b = new D();
D* d1 = static_cast<D*>b; // Valid! d1 is a valid and correct pointer to a D
D* d2 = dynamic_cast<D*>b; // Valid! d2 is a valid and correct pointer to a D
In this example both pointers d1 and d2 will point to a correct typed version of b
The problem comes in the following example:
B* b = new B();
D* d1 = static_cast<D*>b; // Invalid!
D* d2 = dynamic_cast<D*>b; // Valid, but d2 is now a null pointer
Now d1 will point to a data segment of type D*, but the actual data is B*, and will lead to memory issues and corruption.
d2 on the other hand will be a null pointer and can be checked for and handled correctly.
Because dynamic_cast performs runtime type checking it is also slower.
EDIT:
Since dynamic_cast can incurr extra runtime, it can be turned off by instructing the compiler not to include Runtime Type Information.
There are also other cast operators.
Reinterpret Cast
This is the ultimate cast, which disregards all kind of type safety, allowing you to cast anything to anything else, basically reassigning the type information of the bit pattern.
int i = 12345;
MyClass* p = reinterpret_cast<MyClass*> i;
It is very dangerous unless you know what you are doing, and is basically the equivilant of C-cast. Like so;
int i = 0;
void *v = 0;
int c = (int)v; // is valid
int d = static_cast<int>(v); // is not valid, different types
int e = reinterpret_cast<int>(v); // is valid, but very dangerous
And then we have the const_cast<> which removes the const-ness of a variable.