
Migration Guide: C++ 4.1 to C++ 4.2

Table of Contents
-----------------

1.1		The Language
1.2		Recompiling Your Code
1.3		Differences: C++ Early Versions to 4.2
1.4		Other Errors
1.5		Warnings
1.6		Type Warnings
1.7		Other Warnings
1.8		Other Differences
1.9		Templates
1.10		Placing Objects in Shared Memory

This manual is intended to help users of earlier versions of  C++ (3.0, 
3.0.1, 4.0, 4.0.1, and 4.1) port their code to C++ 4.2. You should have 
code that compiles and runs under C++ 3.0, and would like to have it 
compile and run under C++ 4.2.
In most cases, this is as easy as recompiling and relinking the code. 

Note - C++ 4.2 object code is not compatible with C++ 3.0 object code, so
you must recompile your code, including any libraries, which might contain
C++ code. C++ 4.2 object code is compatible with C++ 4.1 and 4.0 object code.

This document resides in the READMEs directory; it is included in both ASCII 
and PostScript(tm) format. The PostScript file has a .ps suffix.

1.1 	The Language

	C++ is an actively changing language. There is an ANSI committee
	hard at work trying to generate a standard for the language, but that
	is still years away. In the mean time, there is the Annotated
	Reference Manual (ARM) and C++ 3.0, although these leave much to
	be desired.

	When writing a compiler you need hard facts about every
	aspect of the language, and when you can't find a precise definition, 
	you have to make the best guess you can. The developers chose to 
	follow the ARM whenever it was clear enough, and to use the ongoing 
	work of the ANSI committee,  as described in the Draft Working 
	Paper (DWP) to help clarify murky areas. The result is their best 
	guess at what the language will become, but you can expect changes 
	with the next release. Sun is actively involved in the ANSI 
	committee and the entire C++ standardization effort, so the 
	developers are tracking its progress closely.

	The compiler supports the entire language described in the ARM, 
	including templates and exceptions. It also includes support for
	wide characters, including a separate type for wchar_t.
	SPARCompiler C++ 4.2 is fully integrated with Solaris 2.x
	internationalization features. There is an extended long integer
	(long long int) and a true long double type.

	Sun is aware that there is a lot of code that compiles with
	some version of C++ 3.0, but is not legal under the current (or
	possibly any) language definition. The compiler detects and flags
	these errors, finding bugs, and generally improving the code
	quality. However, you have to compile and use your
	existing code, so the developers have worked very hard to allow 
	such programs to compile, and to flag these incompatibilities with 
	warning messages. Though changes in the language make it impossible 
	to be completely compatible, this compiler is much more backward-
	compatible than earlier versions of C++ 3.0.

1.2	Recompiling Your Code

	Run your code through the compiler. In the majority of cases, this 
	results in anachronism warnings indicating where the language has
	changed or compiler bugs have been eliminated. Examine the warnings,
	since some may indicate undectected errors in your program. Other
	warnings reflect changes in the language and can be ignored until
	you change the program. Remove the warnings using the following 
	sections guidelines.
	
	In some rare cases, the C++ 3.0 implementation differs from the 
	specification in the C++ Annotated Reference Manual (ARM), or 
	generates incorrect code. In these cases, discussed in the next 
	section, C++ 4.2 is incompatible with C++ 3.0, and you must 
	modify your code.

1.3	Differences: C++ 3.0 to 4.2	


	1.3.1	Error: K&R-style function definitions are no longer allowed

	C++ 3.0 issues warnings; C++ 4.2 issues errors. 



	1.3.2	Error: You cannot set _new_handler via an assignment

	To set _new_handler, call set_new_handler(). If you use your own new 
	handler by assigning to _new_handler, ld issues an error that 
	_new_handler is undefined. Use set_new_handler() to set your own new 
	handler.



	1.3.3	Error: Multiple declarations for A

	C++ 3.0 allows two arguments with the same name in function prototypes. 
	For example:

	extern int foo (int a, int a);

	C++ 4.2 does not allow this.



	1.3.4	Error: Global operator new() is always used when there is no class 
			version

	

	Resolution of operator new() for nested classes in C++ 4.2 is 
	different from C++ 3.0. C++ 3.0 erroneously uses the operator new() 
	from the outer class in preference to the global operator new(), as 
	specified in the ARM.  C++ 4.2 does not duplicate this bug, because 
	to do so would change the semantics of correct programs. For example, 
	the following test case gives different results when compiled with 
	C++ 4.2 and C++ 3.0:

	#include <stdio.h>
	#include <stdlib.h>

	class Foo {
	public:
		void *operator new(size_t sz);
		class Bar {
		public:
			int j;
			Bar(int i) {j = 1;};
		};
	};
	
	void *Foo::operator new(size_t sz) {
		printf("Hi!\n");
		return ::operator new(sz);
	}
	
	int main () {
		Foo::Bar *b = new Foo::Bar(17);
		return 0;
	}

	C++ 3.0 execution produces "Hi!" while C++ 4.2 produced no output. 

	Solution: In the unlikely case that your program depends on this 
	behavior, define Foo::Bar::operator new() and call 
	Foo::operator new() from the new function.



	1.3.5	Error: typedef names are not structure keys

	

	C++ 3.0 and C++ 4.2 differ in the treatment of typedef names for 
	structure types. C++ 3.0 treats the typedef name as a struct name. 
	For example, you could write:

	typedef struct { int x; } A;
	struct A avar;

	The Draft Working Paper (DWP) and ARM state that the second 
	declaration declares a new structure name A. This is an error since 
	there is already an existing typedef name A. The result is:

	Error: Multiple declaration for A.
	Error: The type A is incomplete.

	These errors show up differently when there are local scopes 
	involved, and interpreting the code the same way as C++ 3.0 can 
	actually change the meaning of a legal program. The following 
	code shows some of the confusion that may arise.

	typedef struct { int x; } A;
	void bug () {
		A ** ptpt;
		typedef struct A* Xss; // Declares a local struct A
		ptpt = (Xss*) new Xss[2]; // error here
		*ptpt = (A*) new(A); // errors
	}

	The error messages look like this:
	
	line 5: Error: Cannot assign A(local)** to A**.
	line 6: Error: The type "A(local)" is incomplete.
	line 6: Error: Cannot assign A(local)* to A*.
	
	Solution: Use structure tags instead of typedef names. 
	To leave the typedef name for C compatibility, add the structure 
	name, and use it in both places:
	
	typedef struct A { int x; } A;



	1.3.6	Error: Redefining AAAA after use in BBBB


	C++ contains rules that prohibit any redefinition of an outer 
	scope name that has been used in the class. For example:
	
	typedef int TI;
	class C {
		TI iv;
		float TI;
	};
	
	or, using the same typedef:
	
	class D {
		TI TI;
	};
	
	Both cases produce an error message:
	
	Error: Redefining TI after use in C
	
	Both cases are legal in C. C++ 3.0 does not detect this situation 
	at all.  C++ 4.2 always detects the situation, and for classes, 
	where the usage could be disastrous, reports an error. For structs 
	that use no member functions or other C++ features, the compiler 
	gives a warning. 

	Solution:  Change one of the names.
	


	1.3.7	Error: Cannot assign int(*)(...) to int(*)(int, char).


	C++ 3.0 has a bug that allows the assignment in the following 
	program fragment:
	
	int (*pfp)(int, char);
	extern int foo(int, char);
	void func() {
		pfp = (int (*)(...))foo;       // error
	//	pfp = (int (*)(int, char))foo;    this works
	}
	
	This error is not detected in a direct cast as the right hand side 
	of an assignment, and pointers of type int(*)(...) cannot be 
	assigned to other pointers to functions. This bug does not exist 
	in C++ 4.2.


1.4	Other Errors


	1.4.1	Error: Cannot return int from a function which should return char*


	The expression (anything, 0) is not a null-pointer constant. For 
	example, the following program results in a compilation error:
	
	int error();
	char * foo() {
		return (error(), 0); // error
		// should be:
		// return (error(),(char*) 0);
		// or:
		// error();
		// return 0;
	}
	
	Solution: Cast zero to the appropriate pointer type, or 
	to pull the constant zero out of the comma expression.


	1.4.2	Error: Cannot use {} to initialize <class name>.


	According to the ARM, it is illegal to initialize a class with a
	base class using the aggregate initialization syntax. C++ 3.0
	used to allow this as long as there were no virtual functions 
	and no constructors. 

	Solution: Write a constructor and initialize the class with that.

1.5	Warnings

	Warnings reflect changes in the language or errors 
	undetected by C++ 3.0. A few warnings reflect areas where the 
	current language definition makes code illegal, but we believe 
	this definition should be changed.


	1.5.1	Warning: AAAA is not accessible from BBBB


	There are several contexts in which this message can appear:

	o	When returning a value of class type. The copy constructor 
		must be accessible even if the compiler eliminates the use 
		of the constructor.  Thus the compiler may warn that C::C 
		(const C&) is not accessible. 

		Solution: Make the constructor public.
	
	o	When initializing a value of class type using the syntax C 
		cv=expression.  The situation is as described in the 
		previous case.
	
	o	When using a private type name. C++ 3.0 frequently does not 
		check access for type names; C++ 4.2 does.  

		Solution: Correct the access of the type or remove 
		the reference.

	o	When allocating a class on the heap using "new", the
		compiler will generate code to delete the storage when an
		exception is thrown. To do this requires access to the
		appropriate "operator delete()". Since some compilers do
		not check this access, and there is library code that 
		depends on not checking this access, C++ 4.2 issues a
		warning instead of an error.
	
	o	Though the ARM and the DWP declare that defining a member of 
		a private nested class outside the class is an error, there 
		is doubt whether it will continue to be in the future.
 
		Solution: Evaluate whether the type itself should be private. 
		If so, you should see no other warnings about access to the 
		type, and this warning can be ignored.  Otherwise, make 
		the type (though not necessarily the members) public.  
		For example:

		class A {
			class B {
					f();
		
			};
		};
		A::B::f()		// warning here
			{ //stuff
			}

	o	C++ 3.0.1 allows the use of a private enumerator as a sub-
		script in the definition of static arrays. For example:

		class Foo {
			enum {Max=27};
			static int b[Max];
		};
		
		int Foo::b[Foo::Max];
		
		C++ 4.2 and the ARM do not allow this. 

		Solution: Make the enumerator public.
                      
	o	C++ 3.0 allows the case where a derived class has a static
		object of its base class and the base class constructor is
		private or protected. C++ 4.2 and the ARM do not allow this.
		The following example illustrates this.

		class Base {
		public:
		    Base(const Base &);
		    ~Base();

		protected:
		    Base(int);
		};

		class Derived : public Base {
		public:
		    Derived(int i): Base (i) {}
		    static const Base xx;
		};

		const Base Derived::xx(1);


		Solutions:

		1. Make Base::Base(int) public, or
		2. Add 'friend class Derived;' to the definition of
		   class Base.




	1.5.2	Warning: Default parameters are not allowed for AAAA


	There are two cases that can cause this warning. The first is 
	putting default parameters on overloaded operators. Such defaults 
	are made illegal by the DWP, though C++ 3.0 allows them. 

	Solution: Remove the parameters from the operators. Since the 
	only way the default parameters can be used is in an explicit 
	call, this solution should cause no problem. 

	The second context is on pointers to functions. The ARM states 
	that default parameters only apply to function declarations, 
	not to pointers to functions. C++ 3.0 allows default parameters 
	on such pointers, but its handling of them is inconsistent.  

	Solution: Remove defaults from function pointer declarations 
	and update any calls that use them.



	1.5.3	Warning: Formal argument AAAA of type BBBB has an 
		inaccessible copy constructor


    		or

		Warning: Formal argument AAAA of type BBBB in call to 
		CCCC has an inaccessible copy constructor

	These messages indicate that the object being passed as an argument 
	cannot be copied, even though the compiler is able to eliminate the 
	copy as an optimization. C++ 3.0 does not diagnose such errors, 
	mostly because the language was not clarified on the situation  
	until fairly recently. 

	Solution: Make the copy constructor accessible, this may 
	indicate an improper use of a class that was never intended to be 
	copied. Check the program logic to determine the proper correction.



	1.5.4	Warning: main() must have a return type of int


	Though main() has always been required to return int, C++ 3.0 does 
	not enforce this. Programs that return some other type may produce 
	unpredictable results. 

	Solution: Change the definition of main() so it returns int.


	1.5.5	Warning: The copy constructor for AAAA should take 
		const AAAA&

	or

		Warning: The copy constructor for argument AAAA of 
		type BBBB should take const BBBB&

		or

		Warning: The copy constructor for argument AAAA of 
		type BBBB in call to CCCC should take 
		const BBBB&

	These warnings occur when the compiler has eliminated a copy 
	constructor that would be illegal if called. C++ 3.0 detects this 
	error when the copy constructor was actually used, but not when 
	it was eliminated. 

	Solution: Since copy constructors that do not take const 
	parameters are seldom desirable, the preferred solution is to 
	modify the copy constructor.


	1.5.6	Warning: Trailing comma in a parameter list

	
	C++ 3.0 does not detect an erroneous trailing comma in an actual 
	parameter list. For example, it allows:

	extern void f(int, int);
	f(1, 2,)
	
	Solution: Remove the extra comma.



	1.5.7	Warning: Temporary created for argument AAAA

		or

		Warning: Temporary created for argument AAAA in call 
			to BBBB

	These warnings indicate the compiler created a temporary value for 
	an argument that was a reference to a non-const type. For example:
	
	extern void f(int&);
	f(1);	// called with a non-lvalue
	
	This is always an error, but was accepted by earlier versions of C++. 
	Even C++ 3.0 missed some cases, so this is a warning rather than an 
	error. The problem may be as simple as an inadvertently omitted const 
	in the declaration or a program logic error.



	1.5.8	Warning: Use of count in delete []


	Earlier versions required an element count in the brackets of 
	delete[]. C++ 4.2 allows this count, but ignores it. 

	Solution: Remove the count.


1.6	Type Warnings


	1.6.1	Warning: AAAA was previously declared extern, not static

	

	This is an error, and in most cases C++ 3.0 diagnosed this error 
	correctly. An exception is a user-defined operator new() or 
	operator delete(). The DWP states that any user-defined global 
	version of operator new() or operator delete () is used by the 
	library as well as the user's code. The functions must be global, 
	so static versions are not allowed. This rule does not apply to 
	placement versions 
	of operator new(), only to the default version.



	1.6.2	Warning: Assigning AAAA to the enum BBBB is obsolete

	

	This anachronism is carried over from C++ 3.0. It is illegal to 
	assign any value to an enumeration variable that is not of the 
	enumerated type. 
	
	Solution: Change your program logic or cast the value to the 
	enumerated type.


	1.6.3	Warning: Attempt to redefine AAAA without using #undef


	Macros cannot be redefined without an intervening #undef.  

	Solution: Insert #undef AAAA before redefining it.



	1.6.4	Warning: Initialization without a class name is 
		now obsolete

	
	This warning is carried over directly from C++ 3.0. It occurs 
	when writing a constructor for a derived class:

	class B {
		B(int);
	};
	class D: public B {
		D(int);
	};
	
	D::D(int i) : (i) {}
	//            ^warning here
	{}
	
	The solution is to name the base class directly in the 
	constructor initializer, as follows:
	
	D::D(int i) : B(i) {}


	1.6.5	Warning: Cannot delete a pointer to a constant (AAAA)


	C++ 3.0 does not detect this error. C++ 4.2 does, but gives you 
	a warning.  

	Solution: Do not delete a pointer to a constant, as it is almost 
	certainly an error.



	1.6.6	Warning: Empty declaration (probably an extra semicolon)

	
	Empty declarations are not allowed, though empty statements are. 
	This is usually the result of an editing error or an incorrect 
	macro invocation. C++ 3.0 does not detect such empty declarations, 
	so this is only a warning.


	1.6.7	Warning: Objects of type AAAA must be initialized

	This warning is produced when you use new() to allocate a const 
	object without providing an initial value or a default 
	constructor, as shown in the following example:

	const int * ip = new const int;
	
	This is an error, since constants of unknown value are not useful. 
	Solution: Add an initializer. The preceding example 
	would then become:
	
	const int * ip = new const int(0);
	
	
	1.6.8	Warning: Temporary used for non-const reference, 
		now obsolete

	
	Earlier versions of C++ allowed the initialization of a non-const 
	reference with an incompatible type or non-lvalue. This is 
	obsolete now, but causes a warning message. To avoid the warning, 
	check your program logic, and if you want a temporary, make an 
	explicit one. For example, convert

	short sv;
	int & ir = sv;
	
	to:
	
	short sv;
	short & ir = sv;
	
	or:
	
	int irtemp = sv;
	int & ir = irtemp;
	
	
	
	1.6.9  Warning: Formal argument AAAA of type BBBB is being 
		passed CCCC

		or

		Warning: Formal argument AAAA of type BBBB in call 
		to CCCC is being passed DDDD

	These warnings indicate that the conversion required to pass the 
	argument is illegal, but that C++ 3.0 did not detect the 
	illegality. Failure to handle const and volatile properly on 
	pointers is a major cause of this problem. 
	 
	Solution: Correct it with an explicit cast, but the error is 
	probably the result of a logic error. Passing a value of type 
	char** to an argument of type const char** is illegal in both 
	C++ and ANSI C. This is not an error or oversight in the 
	standard as such assignments open a hole in the type system 
	and violate const safety.

1.7	Other Warnings


	1.7.1	Warning: Undefined character escape sequence

	
	The only string or character constant escape sequences which are 
	allowed in C++ are:

	Table 1-1	Escape Sequences

	newline          NL(LF)    \n

	horizontal tab   HT        \t

	vertical tab     VT        \v

	backspace        BS        \b

	carriage return  CR        \r

	form feed        FF        \f

	alert            BEL       \a

	backslash        \         \\

	question mark    ?         \?

	single quote     '         \' 

	double quote     \"        \"

	octal number     ooo       \ooo

	hex number       hhh       \xhhh

	The effect of any other escape sequence is undefined. C++ 4.2, 
	like C++ 3.0, has replaced the entire escape sequence with the 
	character following the backslash, which may or may not be what 
	was intended. 

	Solution: Determine the intention of the code and substitute 
	the correct character, possibly using a hex escape sequence.



	1.7.2	Warning: Use AAAA:: for access to BBBB


	Access to a nested type without an appropriate qualifier is 
	allowed for compatibility with earlier versions of C++. Each 
	such reference is flagged with this warning. 

	Solution: Use explicit qualification when using the nested 
	type.


	1.7.3  Warning: Using AAAA to initialize BBBB


	C++ 3.0 was lax in its type checking, particularly when pointers 
	to const were involved. Passing a value of type 
	char** to an argument of type const char** is illegal in both 
	C++ and ANSI C. This is not an error or oversight in the standard 
	as such assignments open a hole in the type system and violate 
	const safety. It is legal in C++ to pass a value of type const char**
	to a parameter of type const char* const*.

	Solution: Failure to handle const and volatile properly on pointers
	is a major cause of thius problem. You can usually correct it with
	an explicit cast, but the error is probably the result of a logic
	error.


	1.7.4	Warning: A declaration does not specify a tag or an identifier

	
	ANSI C introduced the restriction that a declaration must define 
	at least a tag or an identifier. The ARM is less precise, stating 
	that a declaration introduces one or more names into a program. 
	A declaration such as extern int; is useless and therefore 
	flagged as an anachronism. 

	Solution: Eliminate the extraneous code.

1.8	Other Differences 

	There are other difference between C++ 3.0 and C++ 4.2.


	1.8.1	operator = ()

	C++ 3.0 accepts any operator =() taking any arguments as a 
	legitimate assignment operator for a class. C++ 4.2 and the 
	DWP accept declarations of the form X::operator=(X&).

	1.8.2	Initializing Non-Aggregate Classes

	C++ 3.0 allows the use of initializer lists with non-aggregate 
	classes. This use is not allowed by the ARM (see the ARM, 
	Section 8.4.1). C++ 4.2 enforces this rule. For example, 
	the following is illegal:

	class base {
		public:
	
		const char *name;
		unsigned int i1;
		unsigned int i2;
		unsigned int i3;
	};
	
	class foo : public base {
		public:
	
		char c;
		unsigned int i4;
	};
	
	static foo array[] = {
		{"hello world", 0, 0, 0, 'c', 0}
	};

	1.8.4	Using the Same Names in Base and Derived Classes

	C++ 3.0 allows an enumerator name defined in a base class to 
	be used as a derived class name. The following test case
	compiles without errors with C++ 3.0, but not with C++ 4.2:

	class foo {
	public:
	    typedef enum {
	      bar,
	      foobar
	    } footype;
	};

	class bar  :  public foo {
	public:
	  bar();
	  ~bar();
	  bar(const bar &b);         // Error here
	  bar &operator=(const bar &b); // Error here
	};

	You can distinguish the name 'bar' in the derived class by 
	using the keyword class as follows:

	class foo {
	public:
	  typedef enum {
	    bar,
	    foobar
	  } footype;
	};
	class bar : public foo {
	public:
	  bar();
	  ~bar();
	  bar(const class bar &b);
	  class bar &operator=(const class bar &b);
	};
1.9	Templates

	If you are using templates with C++ 3.0, you may notice some 
	differences when you move to C++ 4.2. C++ 3.0 generates 
	(or instantiates) template functions when the program is being 
	linked. A separate processor examines the object and library 
	files, determines which template functions are needed, then uses 
	the compiler to instantiate them. C++ 4.2 instantiates at 
	compile time, generating those template instantiations needed by 
	the module being compiled.

	1.9.1   Link Order When Using Templates

	The 4.0.1 compiler had an error in constructing the link line
	when templates were involved. In these cases, the old compiler
	would automatically place archives at the end of the supplied
	(and inserted template) object files. This could have unknown
	consequences when link order was important. The new compiler
	leaves the link order exactly as supplied, and only inserts
	template object files before the first non-object file (such as
	an archive or shared library).


	1.9.2	Specialization Registration

	A specialization of a template is a user-defined version of a 
	template that is normally generated by the compilation system. 
	For example, for the template function:

	template <class T> T foo ( T data );

	A specialized version is:

	int foo ( int data );

	The compiler cannot differentiate between the declaration of a 
	normal function and a template function. As a result, a special 
	file, the options file, is available so that these special-
	izations can be registered with the compiler. This options
	file resides in the template database, and contains many options 
	that can determine how templates are generated. The options 
	used to register specializations look like this for the above 
	code fragment:

	special foo(int);
	
	The information needed to properly handle specializations of 
	templates is covered in depth in the C++ User's Guide.

	1.9.3	Template Repositories

	Generated templates and their supporting files are stored in a 
	directory, the template database. Except for the options file, 
	all the files in the database are object files and state 
	information files, maintained by the compiler. The difference 
	between using the template database in C++ 4.2 versus C++ 3.0 
	is: when you use the -ptr option to specify the template 
	database path, the path includes the database, named Templates.DB. 
	For example:

	In C++ 3.0:

	-ptrMyDatabase

	corresponds to a database located in ./MyDatabase.

	In C++ 4.2:

	-ptrMyDatabase

	 corresponds to a database located in ./MyDatabase/Templates.DB.

	1.9.4	Central Database

	You can use a central database to store generated templates. 
	Do this by using the -ptr command-line directive to specify the 
	location of your database. The inherent problem with a central 
	database is that dependencies, types, and environmental data can 
	change between executables sharing a common template and template 
	database. Changes can lead to confusion, strange behavior at 
	runtime, and missing data in the database. Template objects and 
	dependencies in the relevant state-information files are based 
	on template and type names. Because of potential conflicts 
	between targets and violations of the one definition rule, 
	using templates across multiple targets may lead to unexpected 
	behavior.

	1.9.5	Multiple Databases

	The template sources used during instantiation must be locatable 
	from the directory where the referencing module is compiled. Use 
	multiple databases by specifying multiple -ptr options on the 
	command-line. The first -ptr option is the writeable template 
	database. Whenever multiple databases are involved, specify -ptr 
	as the first -ptr option. See the C++ User's Guide for details.

	It is recommended that you not use multiple -ptr options on the
	command line when using templates. Although this should work 
	with the current version of the compiler, it is not guaranteed
	to work in future releases.

1.10	Placing Objects in Shared Memory

	Placing objects with virtual functions into shared memory 
	requires that the virtual tables needed by those objects be at 
	the same virtual address in all tasks that refer to the objects. 
	To achieve this, control virtual table generation using the +e0 
	and +e1 command-line flags. +e0 prevents generation of virtual 
	tables. +e1 generates virtual tables for every class defined in 
	that compilation unit. Follow these steps:

	1.	Create a file containing only class definitions.

	2.	Compile the file with +e1, generating an object file 
		containing only virtual tables.

	3.	Place the object file at the appropriate spot in virtual 
		memory.

	In C++ 4.2, the exception-handling code generates some internal 
	class objects, so the compilation must include -noex as well as +e1.

	For example, assume that you have header files type1.h and type2.h, 
	and that all classes used within the program are defined in one of 
	those files.  You can compile most of the program using:
	
	CC -c +e0 a.cc b.cc ...
	
	and create a file vt.cc containing:
	
	  #include "type1.h"
	  #include "type2.h"
	
	and compile it with:
	
	CC -c +e1 -noex vt.cc
	
	The file vt.o contains the virtual tables needed by the program.
	
	If you want to generate the virtual tables for the exception data 
	structures, omit the -noex option on the CC command-line.
