Q:

Overloading operators with non-member functions

The answer to this question seems to escape me, but how do you go about overloading with non-member functions.  Do you just create a program level function and where ever the prototype (or definition) exists the operator is overloaded for that class type?

A:

With a member function, this would be the left hand side parameter, meaning your operator would only have one argument (or none for unary operators). With a freestanding function, you must supply either two or one arguments for binary or unary operators, respectively.
A good example is the << operator for streams:
class T;

// ...

std::ostream & operator<<(std::ostream &os, const T &val)
{
    // ...
    return os;
}

Here, os is the left hand side parameter, and val is the right hand side one. 
As for "where", the operator must be defined where you use it. Generally, put them at the same place as the type you're overloading the operators for.
EDIT:
For non trivial operators (arithmetic operations on primitive types), operators are syntactic sugar for function calls. When you do this:
std::cout << "Hello";

It's like writing that:
operator<<(std::cout, "Hello");

But more readable.
For member operators, the left parameter will be this (and that's why member operators have one less argument).

