Hi,
First of all, remember that programming languages are described by formal specifications; the more popular ones are even standardized by organizations such as ISO, ANSI, and/or ECMA. These specifications define the grammar of the language, its semantic properties, and how complying programs must behave. Depending on the goals of the programming language, the latter might (intentionally) not be detailed for all possible scenarios. In order to explain how portability works, I'll need to define a couple of terms:
1. Implementation-defined behavior. If something exhibits this type of behavior, then the language implementation (i.e., the compiler) must document some consistent behavior. E.g., in C++, if you wish to shift a negative value to the right, the result might vary depending on your compiler/platform due to the different ways architectures may represent signedness, the fact that arithmetic shifts might cause overhead on a particular architecture, etc.
2. Undefined behavior. If something exhibits this type of behavior, the implementation is free to do whatever it wants: usually a program crash (but not always). E.g., in C++, if you do something like the following:
*(unsigned char *)0xB8000 = 'A'; // Write 'A' to memory address 0xB8000.
then you will have caused both implementation-behavior (by casting 0xB8000 into a pointer), and undefined behavior (by using the pointer to write to a memory address not part of an object). Let's focus on the latter. In UNIX, this would cause a segfault, according to POSIX (the standard which defines the UNIX environment). However, under other circumstances, this technique can be useful for using things like memory-mapped I/O; this particular line would interact with VGA hardware, which C++ has no knowledge of, as it is supposed to work with a variety of hardware and software.
For Java, performance is not a goal of the language. However, portability is. The behavior of the JVM (Java Virtual Machine) is explicitly defined such that programs will always behave the same regardless of the underlying platform (if any---there are CPUs running Java bytecode out there). Long story short, you don't really need to worry about portability when using Java.
For C++, performance and the ability to perform systems programming are imperative. Hence, care is to be taken when using certain features. For a program to be fully portable, it must only use the standard library and no implementation-defined or undefined behavior. This is obviously not very realistic: if no programs used undefined behavior we wouldn't have libraries interacting with the OS (since the C++ standard has no knowledge about any OSes) or even an OS to interact with, for that matter. So, what to do?
a. Unless portability is not very important, don't use undefined features except for those in cross-platform libraries. If that's not possible, at least try to separate/isolate unportable code using conditional compilation (using either things like #ifdef or build system magic).
b. Don't make any assumptions. E.g., don't assume that int is a 32-bit type, it's size in bytes is sizeof (int); don't assume that a byte is 8 bits wide, its length is CHAR_BIT (an implementation-specific macro defined in
); don't assume any specific character set (e.g., ASCII), etc.
c. Never use compiler-specific extensions (there are always better ways of achieving whatever it is you're trying to do). For example, don't use things like Borland's conio.h header file or GCC's __attribute__((packed)). The number one reason for which these extensions exist is that if you use them in your code base and your project gets big, you won't switch to a new compiler vendor because there's just too much code to refactor. Basically, they want you to tie your project to their compiler.
d. Don't use inline assembly unless you have a really good reason for doing so. Assembly is architecture-specific, its syntax is assembler-specific, and the implementation of the asm keyword in C++ is both optional and implementable in a variety of ways (e.g., MSVC++ uses asm blocks, while GCC uses an infamous atrocity).
As long as you write standards-compilant code, it is irrelevant which features you use. As for which libraries to use, that really depends on what you need so I can't comment on that. The most popular C++ libraries are Boost and Qt, both of which are pretty general-purpose and cross-platform. A good start, at any rate!
Cheers,
Bogdan