C++ Programming Guide |
Program Organization
The file organization of a C++ program requires more care than is typical for a C program. This chapter describes how to set up your header files, inline function definitions, and template definitions.
2.1 Header Files
Creating an effective header file can be difficult. Often your header file must adapt to different versions of both C and C++. To accommodate templates, make sure your header file is tolerant of multiple inclusions (idempotent), and is self-contained.
2.1.1 Language-Adaptable Header Files
You might need to develop header files for inclusion in both C and C++ programs. However, Kernighan and Ritchie C (K&R C), also known as "classic C," ANSI C, Annotated Reference Manual C++ (ARM C++), and ISO C++ sometimes require different declarations or definitions for the same program element within a single header file. (See the C++ Migration Guide for additional information on the variations between languages and versions.) To make header files acceptable to all these standards, you might need to use conditional compilation based on the existence or value of the preprocessor macros
__STDC__
and__cplusplus
.The macro
__STDC__
is not defined in K&R C, but is defined in both ANSI C and C++. Use this macro to separate K&R C code from ANSI C or C++ code. This macro is most useful for separating prototyped from nonprototyped function definitions.
#ifdef_ _STDC
_ _int function(char*,...); // C++ & ANSI C declaration#elseint function(); // K&R C#endif
The macro
__cplusplus
is not defined in C, but is defined in C++.
Note Early versions of C++ defined the macroc_plusplus
instead of _ _cplusplus
. The macroc_plusplus
is no longer defined.
Use the definition of the __
cplusplus
macro to separate C and C++. This macro is most useful in guarding the specification of anextern
"C"
interface for function declarations, as shown in the following example. To prevent inconsistent specification ofextern
"C"
, never place an#include
directive within the scope of anextern
"C"
linkage specification.
#include "header.h"... // ... other include files ...#if defined(_ _cplusplus
)extern "C" {#endifint g1();int g2();int g3()#if defined(_ _cplusplus
)}#endif
In ARM C++, the
__cplusplus
macro has a value of 1. In ISO C++, the macro has the value 199711L (the year and month of the standard expressed as along
constant). Use the value of this macro to separate ARM C++ from ISO C++. The macro value is most useful for guarding changes in template syntax.
// template function specialization#if_ _cplusplus
< 199711Lint power(int,int); // ARM C++#elsetemplate <> int power(int,int); // ISO C++#endif
2.1.2 Idempotent Header Files
Your header files should be idempotent. That is, the effect of including a header file many times should be exactly the same as including the header file only once. This property is especially important for templates. You can best accomplish idempotency by setting preprocessor conditions that prevent the body of your header file from appearing more than once.
#ifndef HEADER_H#define HEADER_H/* contents of header file */#endif
2.1.3 Self-Contained Header Files
Your header files should include all the definitions that they need to be fully compilable. Make your header file self-contained by including within it all header files that contain needed definitions.
#include "another.h"/* definitions that depend on another.h */
In general, your header files should be both idempotent and self-contained.
#ifndef HEADER_H#define HEADER_H#include "another.h"/* definitions that depend on another.h */#endif
2.1.4 Unnecessary Header File Inclusion
Programs written in C++ typically include many more declarations than do C programs, resulting in longer compilation times. You can reduce the number of declarations through judicious use of several techniques.
One technique is to conditionally include the header file itself, using the macro defined to make it idempotent. This approach introduces an additional interfile dependence.
#ifndef HEADER_H#include "header.h"#endif
Note System header files often include guards of the form_Xxxx
, whereX
is an uppercase letter. These identifiers are reserved and should not be used as a model for constructing macro guard identifiers.
Another way to reduce compilation time is to use incomplete class and structure declarations rather than including a header file that contains the definitions. This technique is applicable only if the complete definition is not needed, and if the identifier is actually a class or structure, and not a typedef or template. (The standard library has many typedefs that are actually templates and not classes.) For example, rather than writing:
#include "class.h"a_class* a_ptr;
write:
class a_class;a_class* a_ptr;
(If
a_class
is really a typedef, the technique does not work.)One other technique is to use interface classes and factories, as described in the book Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma (Addison-Wesley, 1994).
2.2 Inline Function Definitions
You can organize your inline function definitions in two ways: with definitions inline and with definitions included. Each approach has advantages and disadvantages.
2.2.1 Function Definitions Inline
You can use the definitions-inline organization only with member functions. Place the body of the function directly following the function declaration within the class definition.
class Class{int method() { return 3; }};
This organization avoids repeating the prototype of the function, reduces the bulk of source files and the chance for inconsistencies. However, this organization can introduce implementation details into what would otherwise be read as an interface. You would have to do significant editing if the function became non-inline.
Use this organization only when the body of the function is trivial (that is, empty braces) or the function will always be inline.
2.2.2 Function Definitions Included
You can use the definitions-included organization for all inline functions. Place the body of the function together with a repeat (if necessary) of the prototype. The function definition may appear directly within the source file or be included with the source file
class Class {int method();};inline int Class::method() {return 3;}
.This organization separates interface and implementation. You can move definitions easily from header files to source files when the function is no longer implemented inline. The disadvantage is that this organization repeats the prototype of the class, which increases the bulk of source files and the chance for inconsistencies.
2.3 Template Definitions
You can organize your template definitions in two ways: with definitions included and with definitions separated. The definitions-included organization allows greater control over template compilation.
2.3.1 Template Definitions Included
When you put the declarations and definitions for a template within the file that uses the template, the organization is definitions-included. For example:
main.cc
template <class Number> Number twice( Number original );template <class Number> Number twice( Number original ){ return original + original; }int main( ){ return twice<int>( -3 ); }
When a file using a template includes a file that contains both the template's declaration and the template's definition, the file that uses the template also has the definitions-included organization. For example:
Note It is very important to make your template headers idempotent. (See Section 2.1.2 "Idempotent Header Files"".)
2.3.2 Template Definitions Separate
Another way to organize template definitions is to keep the definitions in template definition files, as shown in the following example.
Template definition files must not include any non-idempotent header files and often need not include any header files at all. (See Section 2.1.2 "Idempotent Header Files"".)
Note Although it is common to use source-file extensions for template definition files (.c
,.C
,.cc
,.cpp
,.cxx
), template definition files are header files. The compiler includes them automatically if necessary. Template definition files should not be compiled independently.
If you place template declarations in one file and template definitions in another file, you have to be very careful how you construct the definition file, what you name it, and where you put it. You might also need to identify explicitly to the compiler the location of the definitions. Refer to C++ User's Guide for information about the template definition search rules.
Sun Microsystems, Inc. Copyright information. All rights reserved. Feedback |
Library | Contents | Previous | Next | Index |