United States |
Previous | Contents | Index |
If your program tries to initialize a nonconstant reference with a temporary object, the compiler generates a warning. For example:
struct A { A(int); }; void f(A& ar); void g() { f(5); // warning!! } |
When a static member is accessed through a member access operator, the expression on the left side of the dot (.) or right arrow (->) is not evaluated. In such cases, the compiler creates code that calls the static member function to handle the destruction of a class type temporary; the compiler does not create temporary destructor code. For example:
struct A { ~A(); static void sf(); }; struct B { A operator ()() const; }; void f () { B bobj; bobj().sf(); // If 'bobj()' is evaluated, a temporary of // type 'A' is created. } |
Compaq C++ optimizes the implementation of exception handling for normal execution, as follows:
In Compaq C++, a procedure with handlers has no intrinsic overhead. For example, procedures with handlers do not have frame pointers or additional register usage.
Some procedures without explicit handlers may have implicit handlers. The compiler creates a handler for each automatic object that has a destructor. The compiler also creates handlers for constructors that initialize subobjects that have destructors. In such a constructor, the compiler creates a handler for each member with a destructor, and a handler for each base class with a destructor.
The -nocleanup option suppresses generation of such implicit handlers, which results in an executable file that is slightly smaller. You should use this option for programs that do not use exception handling or that do not require destruction of automatic objects during exception processing.
Exception specifications in function prototypes that conflict with
function definitions are illegal. Chapter 7 describes how
Compaq C++ handles such conflicts. Beware of such conflicting
exception specifications, particularly if you have exception
specifications in prototypes that are in header files accessible to
other programs.
2.3.19 File Inclusion (§r.16.4)
The #include directive inserts external text into the macro stream delivered to the Compaq C++ compiler. Programmers often use this directive to include global definitions for use with Compaq C++ functions and macros in the program stream.
The #include directive has the following search path semantics:
This chapter describes the guidelines and procedures for customizing
your language environment. It includes sections on changing your C
header files to work with C++, using 32-bit pointers, organizing your
C++ files, interfacing to other programming languages, and designing
upwardly compatible C++ classes.
C header files that already conform to ANSI C standards must be
slightly modified for use by Compaq C++ programs. In particular, be
sure to address the following issues:
The following sections provide details on how to properly modify your
header files.
To modify header files, use conditional compilation and the extern specifier.
When programming header files to be used for both C and C++ programs,
use the following convention for predefined macros. The system header
files also provide an example of correct usage of the predefined macros.
3.1 Using Existing C Header Files
3.1.1 Providing C and C++ Linkage
#if defined __cplusplus /* If the functions in this header have C linkage, this * will specify linkage for all C++ language compilers. */ extern "C" { #endif extern int func1(int); extern int func2(int); . . . #if defined __cplusplus } /* matches the linkage specification at the beginning. */ #endif |
See §r.7.4 of The C++ Programming Language, 2nd Edition for more information on linkage
specifications.
3.1.2 Resolving C++ Keyword Conflicts
If your program uses any of the following C++ language keywords as identifiers, you must replace them with nonconflicting identifiers:
asm | friend | private | this |
catch | inline | protected | throw |
class | new | public | try |
delete | operator | template | virtual |
Distinctions between ANSI C and C++ include slight differences in rules concerning scope. Therefore, you may need to modify some ANSI C header files to use them with C++.
The following sample code fragment generates an error regarding incompatible types, but the root cause is the difference in scope rules between C and C++. In ANSI C, the compiler promotes tag names defined in structure or union declarations to the containing block or file scope. This does not happen in C++.
struct Screen { struct _XDisplay *display; }; typedef struct _XDisplay { // ... } Display; struct Screen s1; Display *s2; main() { s1.display = s2; } |
The offending line in this sample is s1.display = s2. The types of s1.display and s2 are the same in C but different in C++. You can solve the problem by adding the declaration struct _XDisplay; to the beginning of this code fragment, as follows:
struct _XDisplay; // this is the added line struct Screen { struct _XDisplay *display; }; typedef struct _XDisplay { // ... } Display; // ... |
DEC C has special built-in macros defined in the header files <stdarg.h> and <varargs.h> . These step through the argument list of a routine.
Programs that take the address of a parameter, and use pointer
arithmetic to step through the argument list to obtain the value of
other parameters, assume that all arguments reside on the stack and
that arguments appear in increasing order. These assumptions are not
valid for Compaq C++. Furthermore, the macros in
<varargs.h>
can be used only by C functions with old-style definitions that are not
legal in C++. To reference variable-length argument lists, use the
<stdarg.h>
header file.
3.2 Using Compaq C++ with Other Languages
The following are suggestions regarding the use of Compaq C++ with other languages:
extern "C" int myroutine(int, float); |
cxx -c tiny.cxx cxx -v tiny.o |
/usr/lib/cmplrs/cxx/cc -G 8 -g0 -O1 -call_shared \ /usr/lib/cmplrs/cxx/_main.o tiny.o -v -lcxxstd -lcxx -lexc \ |& /usr/lib/cmplrs/cxx/demangle |
/usr/lib/cmplrs/cc/ld -g0 -O1 -call_shared /usr/lib/cmplrs/cc/crt0.o \ /usr/lib/cmplrs/cxx/_main.o tiny.o -lcxxstd -lcxx -lexc -lc |
/usr/lib/cmplrs/cxx/_main.o -lcxxstd -lcxx -lexc |
/usr/lib/cmplrs/cc/crt0.o ... -lc |
With linkage specifications, you can both import code and data written
in other languages into a Compaq C++ program and export
Compaq C++ code and data for use with other languages. See §4.4
of The C++ Programming Language, 2nd Edition for details on the extern
"C" declaration.
3.4 How to Organize Your C++ Code
This section explains the best way for Compaq C++ users to organize
an application into files; it assumes that you are using automatic
instantiation to instantiate any template classes and functions.
3.4.1 Code That Does Not Use Templates
The general rule is to place declarations in header files and place definitions in library source files. Thus, the following items belong in header files:
The following items belong in library source files:
Header files should be directly included by modules that need them. Because several modules may include the same header file, a header file must not contain definitions that would generate multiply defined symbols when all the modules are linked together.
Library source files should be compiled individually and then linked into your application. Because each library source file is compiled only once, the definitions it contains will exist in only one object module and multiply defined symbols are thus avoided.
For example, to create a class called "array" you would create the following two files:
Header file, array.h:
// array.h #ifndef ARRAY_H #define ARRAY_H class array { private: int curr_size; static int max_array_size; public: array() :curr_size(0) {;} array(int); }; #endif |
Library source file, array.cxx:
// array.cxx #include "array.h" int array::max_array_size = 256; array::array(int size) : curr_size(size) { ...; } |
You would then compile the array.cxx library source file using the following command:
cxx -I./include array.cxx |
The resulting object file could either be linked directly into your application or placed in a library (see Section 3.4.4).
Note that the header file uses header guards, which is
a technique to prevent multiple inclusion of the same header file.
3.4.2 Code That Uses Templates
With the widespread use of templates in C++, determining the proper place to put declarations and definitions becomes more complicated.
Two new types of header files are introduced in Chapter 5: template declaration files and template definition files. Again, the general rule is to place declarations in template declaration files and definitions in template definition files.
Thus, the following items belong in template declaration files:
The following items belong in template definition files:
These guidelines also apply to nontemplate nested classes inside of template classes.
Do not place definitions of nontemplate class members, nontemplate functions, or global data within template definition files; these must be placed in library source files. |
The first three items in the previous list can optionally be placed at the bottom of the template declaration file that contains the corresponding declarations. This will not incur multiply defined symbols when the template declaration file is included by multiple modules. However, this option does not apply to template specialization definitions; these must be placed in a definition template file, or optionally they can be treated as nontemplate code and placed in a library source file as described in Section 3.4.1.
The template definition file should have the same base name as the template declaration file but with a different file extension (such as .cxx). Your template declaration files and template definition files should be placed in the same directory.
For example, the array class from Section 3.4.1, modified to use templates, would now look as follows:
Template declaration file, array.h:
// array.h #ifndef ARRAY_H #define ARRAY_H template <class T> class array { private: int curr_size; static int max_array_size; public: array() :curr_size(0) {;} array(T); }; #endif |
Template definition file, array.cxx:
// array.cxx template <class T> int array<T>::max_array_size = 256; template <class T> array<T>::array(int size) : curr_size(size) { ; } |
Then you would create a source file myprog.cxx that uses the array class as follows:
// myprog.cxx #include <array.h> main() { array<int> ai; // ... } |
Figure 3-1 shows the placement of these files.
Figure 3-1 Placement of Template Declaration and Definition
Files
You would then compile myprog.cxx with
the following command:
cxx -I include myprog.cxx |
In this case, you do not need to create library source files because the static member data and out-of-line members of the array template class are instantiated at the time you compile myprog.cxx.
However you would need to create library source files for the following cases:
Table 3-1 describes where to place declarations and definitions, as discussed in Section 3.4.1 and Section 3.4.2.
Feature | Declaration | Out-of-Line Definition |
---|---|---|
Class | Header file | |
Static member data | Within class declaration | Library source file |
Member function | Within class declaration | Library source file |
Global function | Header file | Library source file |
Global data | Header file | Library source file |
Template class | Template declaration file | |
Static member data of template class | Within template class declaration | Template definition file |
Member function of template class | Within template class declaration | Template definition file |
Global template function | Template declaration file | Template definition file |
Global, nontemplate friend function of template class | Within template class declaration | Library source file |
Specialization of template class | Template declaration file | |
Specialization of template function | Template declaration file | Library source file |
Libraries are useful for organizing the sources within your application as well as for providing a set of routines for other applications to use. Libraries can be either object libraries or shareable libraries. Use an object library when you want the library code to be contained within an application's image; use shareable libraries when you want multiple applications to share the same library code.
Creating a library from nontemplate code is straightforward: you simply compile each library source file and place the resulting object file in your library.
Creating a library from template code requires that you explicitly request the instantiations that you want to provide in your library. See Chapter 6 for details on how to do this.
If you make your library available to other users, you must also supply the corresponding declarations and definitions that are needed at compile time. For nontemplate interfaces, you must supply the header files that declare your classes, functions, and global data. For template interfaces, you must provide your template declaration files as well as your template definition files.
For more information on creating libraries, see the ar(1) reference page and the loader(1) reference page.
Previous | Next | Contents | Index |
|