This question can be divided into two separate questions. "How to write portable code?" and "What are the diverging requirements of major gaming platforms?"
The first question is relatively easy to answer. Recommendations for abstracting your non-portable code are described in the “Portable Code Record” article: http://books.google.ca/books?id=4VOKcEAPPO0C&printsec=frontcover
Turning theory into practice, the Quake 3 source code does a pretty good job of dividing the various platforms into separate areas for the C code base, available at http://www.idsoftware.com/business/techdownloads/ However, it does not show C + templates +, such as abstract interfaces implemented once per platform.
The second part of your question: "What are the diverging requirements of the main gaming platforms?" is tougher. However, it is noteworthy that your biggest areas of change are still your renderer, your audio subsystem, and your network.
Each console platform has a number of certification requirements, available by agreement with the owners of the respective consoles. Requirements lead to consistency in user experience and are not focused on gameplay or high-quality quality problems. For example, your game may need to display a rather interesting animated loading screen, and black screens are unacceptable.
Grab this documentation as soon as possible to make the right choice when designing for a specific console.
Finally, if you cannot access the devkit console, I suggest you port your code to a Mac from Windows. The Mac provides you with an OS port that ensures that you are not tied to Windows, as well as to the processor port, if you support universal binaries. This ensures that your code is not an agent.
If you support both PC and Mac, you will have good opportunities to support the third platform if you get access to it in the future.
Addendum You wrote:
the ideal solution is to reuse as soon as possible, instead of rewriting everything for each platform
In many game porting scenarios, the ideal solution is not to reuse as much code as possible, but to create the optimal code for each platform. The code can be reused between projects and is relatively inexpensive compared to the content that the engine uses. A more reasonable goal is to focus on the lowest common denominator content that works on all platforms unchanged (the build phase that packs the content for the media is fine).