You can use git show for that:
git show HEAD^:main.cpp > old_main.cpp
(Note that there is colon [:] character between HEAD^ and main.cpp.) The <revision>:<path> syntax is described in git rev-parse manpage, next to last point in the “Specifying revisions” section:
<rev>:<path>, e.g.HEAD:README,:README,master:./READMEA suffix
:followed by a path names the blob or tree at the given path in the tree-ish
object named by the part before the colon.:path(with an empty part before the colon)
is a special case of the syntax described next: content recorded in the index at the
given path. A path starting with./or../is relative to the current working directory.
The given path will be converted to be relative to the working tree’s root directory.
This is most useful to address a blob or tree from a commit or tree that has the same
tree structure as the working tree.
Note that <path> here is FULL path relative to the top directory of your project, i.e. the directory with .git/ directory. (Or, to be more exact, to “<revision>“, which in general can be any <tree-ish>, i.e. something that represents tree.)
If you want to use path relative to the current directory, you need to use ./<path> syntax (or ../path to go up from current directory).
Edit 2015-01-15: added information about relative path syntax
You can get in most cases the same output using low-level (plumbing) git cat-file command:
git cat-file blob HEAD^:main.cpp > old_main.cpp