1. What are the static and dynamic polymorphasim and how should they be used?

Polymorphism in general is when a piece of a program is designed to allow multiple different types to be used in it.

Static polymorphism is a use of polymorphism that is determined when the program is constructed (such as the Template system in C++). Once the program is constructed, the choice is made and the type used is known.

Dynamic polymorphism is determined at run time. (Such as a pointer to a base class that allows for descendant class pointers to be passed in. The base class provides the interface and the descendants implement that interface in different ways that are suitable to the specifics of the class.) Decisions are made during run time that choose which type to pass.

The important distinction is deciding at construction (compile) or run time. Generally, a well designed static polymorphism performs better than dynamic, so it is to be preferred when the design makes it possible. If the information to make a choice is not available until run time, dynamic is the choice.



2. What can go wrong when you write thread code and how can you guard against them?

Basically, the big three of threading problems are deadlock, races and starvation.

The simplest deadlock condition is when there are two threads and thread A can't progress until thread B finishes, while thread B can't progress until thread A finishes. This is usually because both need the same two resources to progress, A has one and B has the other. Various symmetry breaking algorithms can prevent this in the two thread or larger circle cases.

Races happen when one thread changes the state of some resource when another thread is not expecting it (such as changing the contents of a memory location when another thread is part way through reading, or writing to that memory). Locking methods are the key here. (Some lock free methods and containers are also good choices for this. As are atomic operations, or transaction based operations.)

Starvation happens when a thread needs a resource to proceed, but can't get it. The resource is constantly tied up by other threads and the one that needs it can't get in. The scheduling algorithm is the problem when this happens. Look at algorithms that assure access.

3. What is the atomic operation and why do they matter?
Atomic operations are operations that can't lose control of the resources they have while executing. Functionally, they are equivalent to operations that happen in a single clock tick on a simple non-pipelined processor. In reality, most take more than a tick but are protected while they execute. They are immune to race conditions, and that makes them useful.

4. Give a short design rationale for STL?
The idea behind the STL is to beat the combinatorial explosion of containers and functions that implement the same data structures and algorithms without forcing all program structures to be objects that are all in the same hierarchy. As long as a type has the needed properties, it works with STL containers or algorithms, no matter what class hierarchies it is or isn't part of.

STL provides a collection of such things that are recognized as both useful and reasonable design. (The picky could point out std::string as a counter-example to good design, here.)

5. what the pure virtual function is and why we need to use it?
A pure virtual member function marks a class as something you will not use on its own, but will only use children derived from it that override the pure virtual function. Any class with a pure virtual function in it cannot be instantiated.

The reason for doing this is for dynamic polymorphism. You need all of the classes that are possibilities to present the same interface to the pieces of the program where polymorphism happens. Often, this is done by creating a class that has nothing but pure virtual functions and making all of the children derive from it. Call it the interface class. You don't want anyone to ever create an instance of the interface class, because even though it has function names available, it doesn't have instructions for what to do when those member functions are called. Since those members are pure virtual, the compiler will not let anyone make an instance of that function, so you are protected from that possible mistake.

The children each need to define overrides for the pure virtual member functions of the parents. If someone writes a child class, and forgets to override even one of these pure virtual functions, trying to create an instance of the child will cause a compile error. Thus, each child has to implement members that provide everything the interface promises, if you want to instantiate the child.