Compatability with Older C++ Compilers

C++ compatability issues with older compilers

For beginners

If you are having trouble with code from this site's C++ tutorials, this section is for you.
Header files
Older compilers may not support newer header files such as
#include <iostream>
This will cause your code to fail to compile, possibly with an error message about not being able to find the file "iostream". You can fix this problem by using the old header file iostream.h:
#include <iostream.h>
If you see a header file that begins with a c, such as cstdlib:
#include <cstdlib>
you should change it by dropping the front c and adding .h:
#include <stdlib.h>
Support for "using namespace std;"
A second issue is that older compilers may not support "namespaces". This is likely to be the case if your compiler suffers from the header file issues listed above. From the perspective of this site's tutorials, all this means is that you should remove the line
using namespace std;
from all examples.

These fixes should enable you to follow the tutorials using an older compiler.

Advanced compatability issues

There are a host of sometimes frustrating compatability issues with older compilers because the C++ standard has added many features over time.
The bool type
Old compilers don't support the bool type or the corresponding keywords true and false that go along with it. The best way to simulate it is probably to use an enum, preferably with the same name (bool) and the same types, true and false:
enum bool { false, true }
Of course, when you run into an up-to-date compiler, you'll need to remove this line of code or it will cause conflicts with the built-in types.
Explicit constructors
Older compilers may not recognize the keyword explicit--in fact, many C++ programmres may not either. The explicit keyword is used to indicate that a one-argument constructor should not be implicitly invoked. What does this mean: well, let's say that you have a class, String, that has a constructor that takes a string literal (e.g., "str literal") and converts it into an object of type String:
String::String( char *str)
{
    // construct a String from the value of str
}

// now use the constructor
String x( "a string" );    // creates a string containing "51"
Now, if you have a function that expects a String, but you pass in a string literal:
void print_string( String x )
{
    // do something to display the string
}

// now try to invoke print_string with a string literal
print_string( "this is not a String object" );
Then the compiler will actually use the one-arg constructor to convert the string literal into a String object! This can be very convenient; it makes the actual C++ standard string class easier to use. But it can also be confusing.

Let's say, for instance, that you decided to include a constructor for your String that takes a number and creates an empty String of that length. Then, if you cal print_string with an integer: print_string( 5 ) you will get the surprising result that it prints five blank spaces.

How do you avoid this? You just make the constructor "explicit", meaning that it needs to be explicitly invoked:
class String
{
    public:
    explicit String (int x) {/* construct a string */}
    String (char *x);
}
Unfortunately, older compilers may not support the use of "explicit", which could be a headache. If you're stuck working with an out-of-date compiler and can't get one that has better support for the C++ standard, your best solution may be to take advantage of the fact that only a single implicit conversion will take place for a given value. You can exploit this by using an intermediate class that implicitly creates an object of each type, and then have your main class implicitly create objects from that class:
class proxy
{
    public:
    proxy(int x) : x(x) {} ;
    getValue() { return x; }

    private:
    int x;

};

class String
{
    // this will be equivalent of explicit
    String(proxy x) { /* create a string using x.getValue(); */ }
}
Why does this work? Well, there are two cases--first, when you try to explicitly create a String:
String my_five_blanks( 5 );
then the proxy class will be implicitly created from 5, and then the correct String constructor will be invoked.

But if you try to call print_value:
print_value( 5 );
then it would require two conversions: one to a proxy, and then one to a String. The compiler won't do this (because otherwise you could get enormously confusing strings of conversions of arbitrary length). Unfortunately, it requires an extra proxy class to work correctly.
Typecasting
Older compilers may not support the new typecasting syntax:
int x = 65;
static_cast<char>( x );
You can often get around this by using the old-style cast:
int x = 65;
(char)x;
Unfortunately, replicating the effect of dynamic_cast can be difficult. With a dynamic_cast, it is possible to safely cast down an inheritance hierarchy from a pointer (or reference) with the static type of a superclass to its dynamic type of a given child class. If the cast cannot succeed because the pointer doesn't point to the correct child class type, then dynamic_cast will either return NULL (if casting a pointer) or throw a bad_cast exception (if casting a reference). On older compilers, you can simulate the syntax using a macro (for readability):
#define DYNAMIC_CAST(type, obj) (type)obj
but you won't get the added safety benefits!