In short
Static vs dynamic binding is about when the exact code to run (i.e. the function's address) is known: at compile-, link- (both "static"), load-, or run-time (both "dynamic").
Polymorphism is firstly about how the exact code to run is known: to qualify as polymorphism, it's necessarily inferred from the type of data being processed. When the "dynamic type" of data is not known until run-time (often because the type is determined by run-time data inputs) dynamic binding must be used, and that requires dynamic polymorphism (aka runtime polymorphism; C++ offers the virtual dispatch mechanism in this category). There are other situations when virtual dispatch is useful even though the types of data being processed are available at compile time - particularly for minimising/eliminating (re)compile times after code changes, and for tuning code "bloat". Anyway, compile-time aka static polymorphism uses what's known about the types at compile time to bind at compile- or link- time (i.e. "statically").
Examples
struct Base { virtual void f(); void g(); };
struct Derived : Base { void f(); void g(); };
Derived d;
d.f(); // if definition's in a shared library, needs dynamic binding
// otherwise (same translation unit, linked object, static lib)
// compiler should optimise to static binding
// (though functionally either would work)
Base* p = factory(data);
p->f(); // dynamic binding - if p points to a Base, use Base::f()
// - if p pointer to a Derived, use Derived::f()
void some_func(const char*); // note: no polymorphism / overloads
some_func("hello world\n");
// if some_func is defined in...
// - shared / dynamic link library, binds dynamically
// - otherwise, static binding
std::cout << "hello world\n"; // static binding
// compile-time polymorphism from (operator) overloading
Discussion
binding normally refers to the time at which the program resolves a function call to a specific function implementation's machine code:
"binding" - and "currying" - are also used to describe the stipulation of arguments to functors (search for "binding" in Stroustrup's C++11 FAQ)
The only situations in which C++ programs bind function calls dynamically are:
when a dynamic library is used, in which case the binding may be done by the Operating Systems loader before main()
is called, or explicitly in code using dlsym
(or similar OS-specific function), which returns a function pointer to use to call a function found in a dynamic library (.so, .dll, ...).
in virtual dispatch, when a virtual member function is found at run-time, typically by following a pointer from the data-object to a virtual dispatch table where the function pointer's recorded
when function pointers are used explicitly by the programmer
In other situations, binding is static: the compiler itself writes a jmp or call to a specific memory address/offset (whether absolute or relative to the Program Counter doesn't matter) into the object or executable it creates, and that is not modified during program loading or execution.
The static / dynamic binding classification only has a little overlap with polymorphism:
virtual dispatch normally uses dynamic binding (but can sometimes be optimised as per Examples above) and
all other forms of polymorphism in C++ (namely overloading, templates, inlined macro expansions) use static binding, but
so does most non-polymorphic code: any "normal" non-virtual call to a function that's not in a shared/dynamic library is resolved at compile time too.