home *** CD-ROM | disk | FTP | other *** search
-
- ΓòÉΓòÉΓòÉ 1. About This Book ΓòÉΓòÉΓòÉ
-
- This book describes the C++ language and contains language reference material
- to go along with the IBM C/C++ for OS/2 Programming Guide It describes in
- detail the constructs that make up the OS/2 C/C++ language, and it emphasizes
- the elements of C++ that are not part of the C language.
-
- In this book, the C++ programming language is referred to as C++ +. The IBM*
- C/C++ compiler for OS/2* is referred to as the OS/2 C/C++ compiler.
-
- IMPORTANT
-
- This book is currently being reformatted and adapted to this platform. Some
- references may be incorrect or unresolved.
-
- The following topics are discussed in this chapter:
-
- o Who should use this book
- o How to use this book
- o A note about examples
- o How to read the syntax statements
- o Related documentation
-
-
- ΓòÉΓòÉΓòÉ 1.1. Who Should Use This Book ΓòÉΓòÉΓòÉ
-
- This book is a reference manual for people who are already familiar with the
- C++ language. It is intended for programmers who want to write applications
- under the OS/2 operating system. It does not fully define the language.
-
-
- ΓòÉΓòÉΓòÉ 1.2. How to Use This Book ΓòÉΓòÉΓòÉ
-
- If you are not familiar with the C++ language, you may want to read through
- this book sequentially. If you are familiar with the C++ language and you just
- want specific reference information for some topic, you may want to look
- through the following overview of the chapters:
-
- What is C++ gives a brief overview of the features of the C++ language,
- including a description of the C++ language constructs that support
- object-oriented programming.
-
- Lexical Conventions describes the basic elements of the C++ language.
-
- Experssions and Operators describes the expressions and standard C++ operators
- used in computation.
-
- Declarations describes declarations and declarators. This chapter includes
- descriptions of program linkage, storage classes, fundamental data types, and
- initialization of the fundamental data types.
-
- Standard Conversions describes the standard conversions performed on the
- fundamental data types.
-
- C++ Statements describes the statements used to control the execution sequence
- of programs.
-
- Functions describes the form and use of functions, including function
- declarations and definitions.
-
- C++ Classes describes the concept of classes in C++, including a description of
- the different types of classes, how to declare class objects, and the scoping
- rules for class objects.
-
- Class Members and Friends describes the scoping rules for class members and
- member access rules.
-
- C++ Overloading describes the form and use of overloaded functions and
- overloaded operators.
-
- Special Member Functions describes the member functions that are used to
- create, destroy, convert, initialize, and copy class objects.
-
- Inheritance describes the concept of inheritance, including a description of
- access control for derived and base classes.
-
- Templates describes class templates and function templates.
-
- Exception Handling describes the facilities C++ provides for handling errors
- and other exceptions.
-
- The Preprocessor discusses preprocessor directives.
-
- C-C++ Compatibility summarizes the main differences between American National
- Standard C language definition (ANSI C) and C++.
-
- C++ Grammar Summary provides a complete summary of the grammar used in this
- book.
-
-
- ΓòÉΓòÉΓòÉ 1.3. A Note About Examples ΓòÉΓòÉΓòÉ
-
- Examples illustrating the use of the C/C++ Compiler are written in a simple
- style. They are intended to be instructional and do not attempt to minimize run
- time, conserve storage, or check for errors. The examples do not demonstrate
- all of the possible uses of C++ language constructs. Some examples are only
- code fragments and will not compile without additional code.
-
-
- ΓòÉΓòÉΓòÉ 1.4. How to Read the Syntax Statements ΓòÉΓòÉΓòÉ
-
- Throughout this book, syntax statements describe the form and syntax of C++. A
- complete summary of the C++ grammar used in this book is presented in Appendix
- B
-
- o Syntax statements are read from left to right.
-
- o Optional parameters are contained in [ ] (square brackets).
-
- o Parameters that can be repeated are followed by an ... (ellipsis).
-
- o Keywords appear as bold letters (for example, define) and must be spelled
- exactly as shown.
-
- o Variables appear in italic letters (for example, identifier ) and represent
- user-supplied values or parameters.
-
- o Punctuation marks, parentheses, arithmetic operators, or other symbols that
- you must type as part of the syntax are shown in bold. For example:
-
- .postfix-expression ( [
- expression-list
- ] )
-
- o In general, white space is permitted between language elements. The
- description of the syntax indicates where white space is not allowed.
-
-
- ΓòÉΓòÉΓòÉ 1.5. Related Documentation ΓòÉΓòÉΓòÉ
-
- You may want to refer to the following publications for additional information.
-
-
- ΓòÉΓòÉΓòÉ 1.5.1. IBM Publications ΓòÉΓòÉΓòÉ
-
- o IBM C/C++ for OS/2 Programming Guide
-
- o IBM C/C++ for OS/2 &cpplus. Basic Class Library Guide
-
- o IBM C/C++ for OS/2 &cpplus. IBM Class Libraries: Collection Classes Reference
-
- o IBM C/C++ for OS/2 &cpplus. IBM Class Libraries: User Interface Reference
-
-
- ΓòÉΓòÉΓòÉ 1.5.2. Non-IBM Publications ΓòÉΓòÉΓòÉ
-
- The C++ language was developed by Bjarne Stroustrup of AT&T** Bell
- Laboratories. For more information about the history of the language, refer to
- books and papers written by him.
-
- Many commercial books have been written about the C++ language and more appear
- each month. The authors use varying approaches and emphasis. The following is a
- sample of some of the non-IBM C++ publications that are generally available.
- This sample is not an exhaustive list. IBM does not specifically recommend any
- of these books, and other C++ publications may be available in your locality.
-
- o The Annotated C++ Reference Manual by Margaret A. Ellis and Bjarne
- Stroustrup, Addison-Wesley Publishing Company.
-
- o The C++ Programing Language (Second Edition) by Bjarne Stroustrup,
- Addison-Wesley Publishing Company.
-
- o C++ Primer (Second Edition) by Stanley B. Lippman, Addison-Wesley Publishing
- Company.
-
- At this time, there is no universal standard for the C++ language comparable to
- the C standards. However, a committee of the American National Standard for
- Information Systems (ANSI) is developing one. Their current working paper,
- Working Paper for Draft Proposed American National Standard for Information
- Systems - Programming Language C++ (X3J16/92-0060) was used as a base document
- for developing the OS/2 C/C++ Compiler.
-
- Because C++ evolved from C, you should be aware of the C standards. The
- following documents describe the standards for the C language.
-
- o American National Standard for Information Systems - Programming Language C
- (X3.159-1989) &dnansic. presents the ANSI standard for the C language.
-
- o International Standard C ISO/IEC 9899 &dnisoc. presents the International
- Standards Organization (ISO) standard for the C language.
-
-
- ΓòÉΓòÉΓòÉ 2. Chapter 2. What Is C++? ΓòÉΓòÉΓòÉ
-
- This chapter describes the C++ language, briefly summarizes the differences
- between C and C++, and discusses the principles of object-oriented programming.
- The following topics are discussed in this chapter:
-
- o The C[++ ] language
- o C[++] support for object-oriented programming
- o C[++] programs
- o Declarations and definitions
- o Scope
- o Simple input and output
- o Linkage specifications - linking to non-C[++] programs.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 2.1. The C++ Language ΓòÉΓòÉΓòÉ
-
- C++ is an object-oriented language based on the C programming language. It can
- be viewed as a superset of C. Almost all of the features and constructs
- available in C are also available in C++. However, C++ is more than just an
- extension of C. Its additional features support the programming style known as
- object-oriented programming. Several features that are already available in C,
- such as input and output, are implemented differently in C++.
-
- C++ was developed by Bjarne Stroustrup of AT&T Bell Laboratories. C++ was
- originally based on the definition of the C language stated in The C
- Programming Language by Brian W. Kernighan and Dennis M. Ritchie. This C
- language definition is commonly called K&R C. Since the introduction of C++,
- the American National Standard C language definition (commonly called ANSI C)
- has been developed. The ANSI C definition specifies many of the features that
- K&R left unspecified. Features of ANSI C have been incorporated into the
- current definition of C++, and some parts of the ANSI C definition have been
- motivated by C++.
-
- While there is currently no C++ standard comparable to the ANSI C definition,
- an ANSI committee is working on such a definition. The current draft of the
- American National Standard for Information Systems - Programming Language C++
- is the source document for the upcoming standardization of C++. Developers of
- the &xcomp. are adhering to the current version of the working paper ofthe
- American National Standard for Information Systems - Programming Language C++ .
-
-
- ΓòÉΓòÉΓòÉ 2.2. C++ Support for Object-Oriented Programming ΓòÉΓòÉΓòÉ
-
- Object-oriented programming is a programming approach based on the concepts of
- data abstraction, inheritance and polymorphism. Unlike procedural programming
- techniques, object-oriented programming concentrates not on how something is
- accomplished but instead on what data objects are involved in the problem and
- how they are manipulated. Based on the foundation of data abstraction,
- object-oriented programming allows you to reuse existing code more efficiently
- and increase their productivity.
-
-
- ΓòÉΓòÉΓòÉ 2.2.1. Types and Objects ΓòÉΓòÉΓòÉ
-
- The C++ fundamental types are those found in ANSI C and include int, float, and
- double. In this document, instantiations of data types are referred to as
- objects . As in ANSI C, you must declare an object in C++ before you can use
- it. In C++ code, objects are represented by variables. A variable also
- represents the location in storage that contains the value of an object.
-
- Like ANSI C, C++ allows you to assign new type names by using the typedef
- construct. These new type names are not new types.
-
- C++ also supports the ANSI C non-fundamental types. It extends the definition
- of two of the non-fundamental types, struct and union .
-
-
- ΓòÉΓòÉΓòÉ 2.2.2. Data Abstraction ΓòÉΓòÉΓòÉ
-
- Data abstraction provides the foundation for object-oriented programming. In
- addition to providing fundamental data types, object-oriented programming
- languages allow the user to define their own data types, called user-defined or
- abstract data types. In the C programming language, related data items can be
- organized into structures. These structures can then be manipulated as units of
- data. In addition to providing this type of data structure, object-oriented
- programming languages allow you to implement a set of operations that can be
- applied to the data elements. The data elements and the set of operations
- applicable to the data elements together form the abstract data type.
-
- To support data abstraction, a programming language must provide a construct
- that can be used to encapsulate the data elements and operations that make up
- an abstract data type. In the C++ programming language, this construct is
- called a class . An instance of a class is called an object. Classes are
- composed of data elements called data members and member functions that define
- the operations that can be carried out on the data members.
-
-
- ΓòÉΓòÉΓòÉ 2.2.3. Encapsulation ΓòÉΓòÉΓòÉ
-
- Another key feature of object-oriented programming is encapsulation.
- Encapsulation means a class can hide the details of:
-
- o The representation of its data members
-
- o The implementation of the operations that can be performed on these data
- members.
-
- Application programs manipulate objects of a class using a clearly defined
- interface. As long as this interface does not change, you can change the
- implementation of a class without having to change the application programs
- that use the class. Thus, encapsulation provides the following advantages:
-
- o Users of a class do not have to deal with unnecessary implementation details.
-
- o Programs are easier to debug and maintain.
-
- o Unwanted alterations are prevented.
-
- In C++, encapsulation is enforced by specifying the level of access control for
- each member of a class. Both the data members and member functions of a class
- can be declared public, protected, or private depending on the degree of access
- control required.
-
-
- ΓòÉΓòÉΓòÉ 2.2.4. Inheritance ΓòÉΓòÉΓòÉ
-
- Inheritance lets you reuse existing code and data structures in new
- applications. In C++, inheritance is implemented through class derivation. You
- can extend a library of existing classes by adding data elements and operations
- to existing classes to form derived classes. A derived class has all the
- members of its parent or base class, as well as extensions that can provide
- additional features. When you create a new derived class, you only have to
- write the code for the additional features. The existing features of the base
- class are already available.
-
- A base class can have more than one class derived from it. In addition, a
- derived class can serve as a base class for other derived classes in a
- hierarchy. Typically, a derived class is more specialized than its base class.
-
- A derived class can inherit data members and member functions from more than
- one base class. Inheritance from more than one base class is called multiple
- inheritance .
-
-
- ΓòÉΓòÉΓòÉ 2.2.5. Dynamic Binding and Polymorphism ΓòÉΓòÉΓòÉ
-
- Another key concept that allows you to write generic programs is dynamic or
- late binding. Dynamic binding affects the derivation process and allows each
- user-defined class in an inheritance hierarchy to have a different
- implementation of a particular function. Application programs can then apply
- that function to an object without needing to know the specifics of the class
- that the object belongs to. In C++, dynamic binding hides the differences
- between a group of classes in an inheritance hierarchy from the application
- program. At run-time, the system will determine the specific class of the
- object and invoke the appropriate function implementation for that class.
-
-
- ΓòÉΓòÉΓòÉ 2.2.6. Other Features of C[++ ΓòÉΓòÉΓòÉ
-
- ]
-
- C++ provides several other powerful extensions to the C programming language
- that are not necessarily part of object-oriented programming. Among these
- extensions are:
-
- o Constructors and destructors, which are used to create, initialize and
- destroy class objects.
-
- o Overloaded functions and operators, which provide static or compile-time
- binding of function calls.
-
- o Inline functions, which aid in optimization
-
- o "Pass-by-reference calls", which allow a function to modify its arguments in
- the calling function.
-
- o Template functions and classes, which allow user-defined families of classes
- and compile-time binding of functions
-
- o Exception handling, which provides transfer of control and recovery from
- errors and other exceptional circumstances.
-
-
- ΓòÉΓòÉΓòÉ 2.3. C++ Programs ΓòÉΓòÉΓòÉ
-
- C++ programs contain many of the same programming statements and constructs as
- C programs. C++ has the same built-in data types as C. The scope and storage
- class rules for C also apply in C++. In addition, C and C++ have the same set
- of arithmetic and logical operators.
-
- In C++, a name can identify an object, a function, a set of functions, an
- enumerator, a type, a class member, a template, a value, or a label. A
- declaration introduces a name into a program and can define an area of storage
- associated with that name.
-
- An expression performs some computational action and is composed of operations
- and operands. An expression terminating with a semicolon is called a statement.
- A statement is the smallest independent computational unit. Functions are
- composed of groups of one or more statements.
-
- A C++ program is composed of one or more functions. These functions can all
- reside in a single file or can be placed in different files which are linked to
- each other. In C++, a program must have one and only one function called main()
- .
-
- The following is a simple C++ program containing declarations, expressions,
- statements, and two functions:
-
- #include <math.h> // contains definition
- of abs()
- extern double multiplier, common_ratio; // variable
- declarations
- double geo_series(double a, double r) // function definition
- {
- if (r == 1) // if statement
- return -1.0; // return statement
- else if (abs(r) < 1.0) // else if statement
- return (a / (1 - r)); // statement containing
- // expression
- else return -2.0;
- }
- void main () // program execution begins here
- {
- double sum; // variable definition
- sum = geo_series(multiplier, common_ratio); // function
- call
- // ..
- }
-
-
- ΓòÉΓòÉΓòÉ 2.4. Declarations and Definitions ΓòÉΓòÉΓòÉ
-
- Declarations introduce identifiers into the program. A declaration is a
- definition unless it:
-
- o declares a function without including the function body
-
- o contains the extern storage class specifier and has no initializer or
- function body
-
- o declares a static data member in a class declaration
-
- o declares a class name
-
- o declares a typedef.
-
- The following are only declarations:
-
- extern double d;
- extern int i;
- int bar(int);
- class C;
- typedef float FP;
-
- The following declarations are also definitions:
-
- double d;
- extern int i = 1;
- int bar(int b) {return b;}
- class C { int a;};
- enum direction {vertical, horizontal};
-
- A given function, object, or type can have only one definition. It can have
- more than one declaration as long as all of the declarations match. If a
- function is never called and its address is never taken, then you do not have
- to define it. You can define a given class or enumerator more than once, but
- every definition must be the same.
-
- One of the fundamental differences between C++ and C is the placement of
- variable declarations. Although variables are declared in the same way, in C++
- variable declarations can be placed anywhere in the program. In C, variable
- declarations must come before any other statements in a block. In the following
- example, the variable d is declared in the middle of the main() function:
-
- #include<iostream.h>
- void main()
- {
- int a, b;
- cout << "Please enter three integers" <<
- endl;
- cin >> a >> b;
- int d = a + b;
- cout << "Here is the sum of your two integers
- " << d << endl;
- }
-
- In C++ function declarations, you must declare the number and type of arguments
- that the function takes. This style of function declaration is the same as
- function prototyping in ANSI C. You must declare the type of each argument
- separately. In the following example the function yonge() takes two int
- arguments and returns an int value:
-
- int yonge(int, int);
-
- You can include optional argument identifiers in a function declaration. For
- example:
-
- int yonge(int a, int b);
-
-
- ΓòÉΓòÉΓòÉ 2.5. Scope ΓòÉΓòÉΓòÉ
-
- The area of the code where an identifier is visible is referred to as the scope
- of the identifier. The four kinds of scope are:
-
- o Local
-
- o Function
-
- o File
-
- o Class.
-
- The scope of a name is determined by the location of the name's declaration.
-
- A type name first declared in a function return type has file scope. A type
- name first declared in a function argument list has local scope.
-
- A function name that is first declared as a friend of a class is in the first
- non-class scope that encloses the class. If the friend function is a member of
- another class, it has the scope of that class. A class name first declared as a
- friend of a class has the scope of the class containing the friend declaration.
-
-
- ΓòÉΓòÉΓòÉ 2.5.1. Local Scope ΓòÉΓòÉΓòÉ
-
- A name has local scope if it is declared in a block. A name with local scope
- can be used in that block and in blocks enclosed within that block, but the
- name must be declared before it is used. When the block is exited, the names
- declared in the block are no longer available.
-
- Formal argument names for a function have the scope of the outermost block of
- that function.
-
- If a local variable is a class object with a destructor, the destructor is
- called when control passes out of the block in which the class object was
- constructed.
-
- When one block is nested inside another, the variables from the outer block are
- usually visible in the nested block. However, if an outer block variable is
- redefined in a nested block, the new declaration is in effect in the inner
- block. The original declaration is restored when program control returns to the
- outer block. This is called block visibility.
-
-
- ΓòÉΓòÉΓòÉ 2.5.2. Function Scope ΓòÉΓòÉΓòÉ
-
- The only type of identifier with function scope is a label name. A label is
- implicitly declared by its appearance in the program text and is visible
- throughout the function that declares it.
-
-
- ΓòÉΓòÉΓòÉ 2.5.3. File Scope ΓòÉΓòÉΓòÉ
-
- A name has file scope if its declaration appears outside of all blocks and
- classes. A name with file scope is visible from the point where it is declared
- to the end of the source file. The name is also made accessible for the
- initialization of global variables. If a name is declared extern, it is also
- visible, at linkage time, in all object files being linked. Global names are
- names declared with file scope.
-
-
- ΓòÉΓòÉΓòÉ 2.5.4. Class Scope ΓòÉΓòÉΓòÉ
-
- The name of a class member has class scope and can only be used in the
- following cases:
-
- o In a member function of that class
-
- o In a member function of a class derived from that class
-
- o After the . (dot) operator applied to an instance of that class
-
- o After the . (dot) operator applied to a class derived from that class
-
- o After the -> (arrow) operator applied to a pointer to an instance of that
- class
-
- o After the -> (arrow) operator applied to a pointer to class derived from that
- class
-
- o After the :: (scope) operator applied to the name of a class
-
- o After the :: (scope) operator applied to a class derived from that class.
-
- See "Scope of Class Names" for more details on class scope.
-
-
- ΓòÉΓòÉΓòÉ 2.6. Simple Input and Output ΓòÉΓòÉΓòÉ
-
- Like C, the C++ language has no built-in input and output facilities. Instead,
- input and output facilities for C++ are provided by the I/O Stream Library. For
- compatibility with C, C++ also supports the standard C I/O functions. The I/O
- Stream Library supports a set of I/O operations, written in the C++ language,
- for the built-in types. You can extend these facilities to provide input and
- output functions for user-defined data types.
-
- For a complete description of the I/O Stream Library, see "Introduction to the
- I/O Stream Library" in the Basic Class Library Guide Compiler/6000 Version
- 1.1.1.
-
- There are four standard predefined I/O stream objects that you can use to
- perform standard I/O:
-
- o cout
-
- o cin
-
- o cerr
-
- o clog
-
- You can use these in conjunction with the overloaded << (insertion or output)
- and (extraction or input) operators. In order to use these streams and
- operators, you must include the header file iostream.h. The following example
- prints Hello World! to standard output.
-
- #include<iostream.h>
- main()
- {
- cout << "Hello World!" << endl;
- }
-
- The manipulator endl acts as a newline character, causing any output following
- it to be directed to the next line.
-
-
- ΓòÉΓòÉΓòÉ 2.6.1. Output ΓòÉΓòÉΓòÉ
-
- The cout stream is associated with standard output. You can use the output
- operator in conjunction with cout to direct a value to standard output.
- Successive output operators are concatenated when applied to cout. The
- following example prints out three strings in a row and produces the same
- result as the previous example, printing Hello World! to standard output.
-
- #include<iostream.h>
- main()
- {
- cout << "Hello " << "World" <<
- "!" << endl;
- }
-
- The output operator is defined to accept arguments of any of the fundamental
- data types, as well as pointers, references and array types. You can also
- overload the output operator to define output for your own class types.
-
- The cerr and clog streams direct output to standard error. cerr provides
- unbuffered output, while clog provides buffered output. The following example
- checks for a division by zero condition. If one occurs, a message is sent to
- standard error.
-
- #include<iostream.h>
- main()
- {
- double val1, val2;
- cout << "Divide Two Values" << endl;
- cout << "Enter two numeric values: " <<
- endl;
- cin >> val1 >> val2;
- if (val2 == 0 )
- { cerr << "The second value must be non-zero"
- << endl;
- return;
- }
- cout << "The answer is " << val1 /
- val2 << endl;
- }
-
-
- ΓòÉΓòÉΓòÉ 2.6.2. Input ΓòÉΓòÉΓòÉ
-
- The cin class object is associated with standard input. You can use the input
- operator in conjunction with cin to read a value from standard input. White
- space (including blanks, tabs, and newlines) is disregarded by the input
- operator. For example:
-
- #include<iostream.h>
- main()
- {
- double val1, val2;
- cout << "Enter two numeric values:" <<
- endl;
- cin >> val1 >> val2;
- cout << "The first value entered is "
- << val1
- << " and the second value is "
- << val2 << "." << endl;
- }
-
- If the values 1.2 and 3.4 were entered through standard input, the above
- program prints the following to standard output:
-
- Enter two numeric values:
- 1.2
- 3.4
- The first value entered is 1.2 and the second value is
- 3.4.
-
- Any white space entered between the two numeric values is disregarded by the
- input operator.
-
- The input operator is defined to accept arguments of any of the fundamental
- data types, as well as pointers, references and array types. You can also
- overload the input operator to define input for your own class types.
-
-
- ΓòÉΓòÉΓòÉ 2.7. Linkage Specifications - Linking to non-C++ Programs ΓòÉΓòÉΓòÉ
-
- You can link C++ code to code produced by other compilers by using a linkage
- specification. The syntax is:
-
- linkage-specification:
- extern string-literal
- {
- [declaration-list] }
- extern string-literal declaration
-
- declaration-list:
- declaration
- declaration-list declaration
-
- .* From heading: "String Literals" string-literal is used to specify the
- linkage associated with a particular function. For example,
-
- extern "C" printf(char*,...);
- void main()
- {
- printf("hello\n");
- }
-
- Here the string-literal, "C", tells the compiler that the routine
- printf(char*,...) is a C library function. Note that string literals used in
- linkage specifications are not case sensitive.
-
- The valid values for string-literal include:
-
- "C++" Default
-
- "C" C type linkage
-
- If the value of string-literal is not recognized, C type linkage is used. For
- further details on linkage specifications, see "Using the XL C[++]
- Compiler/6000 with Other Programming Languages" in the Programming Guide
- Compiler/6000.
-
-
- ΓòÉΓòÉΓòÉ 3. .Chapter 3. Lexical Conventions ΓòÉΓòÉΓòÉ
-
- This chapter describes the following basic elements of C++ :
-
- o Tokens
- o The C++ character set
- o Trigraph sequences
- o Digraph sequences
- o Escape sequences
- o Comments
- o Identifiers
- o Keywords
- o Literals.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 3.1. Tokens ΓòÉΓòÉΓòÉ
-
- You can view C++ source code as a sequence of tokens. There are five different
- types of tokens:
-
- o Identifiers
-
- o Keywords
-
- o Literals
-
- o Operators
-
- o Other separators.
-
- Adjacent identifiers, keywords and literals must be separated with white space.
- White space includes blanks, horizontal and vertical tabs, newlines, formfeeds
- and comments.
-
-
- ΓòÉΓòÉΓòÉ 3.2. The C++ Character Set ΓòÉΓòÉΓòÉ
-
- C++ source programs use the following character set:
-
- o The lowercase and uppercase letters of the English alphabet.
-
- a b c d e f g h i j k l m n o p q r s t u v w x y
- z
-
- A B C D E F G H I J K L M N O P Q R S T U V W X Y
- Z
-
- C++ treats lowercase and uppercase letters as distinct characters. If you
- specifya lowercase a, an uppercase A cannot be substituted.
-
- o The digits:
-
- 0 1 2 3 4 5 6 7 8 9
-
- o The following special characters:
-
- ! " # % & ' ( ) * + , - . / :
-
- ; < = > ? [ \ ] ^ _ { } ~ |
-
- where the # character is used for preprocessing only, and the _ character is
- treated as a normal letter.
-
- o The space character.
-
- o The control characters that represent horizontal and vertical tabs, newlines,
- and formfeeds.
-
- o In extended mode, the &xcomp. allows the $ character to be used in
- identifiers to facilitate calls between different XL languages. See
- "Interlanguage Calling Conventions" in the Programming Guide
-
-
- ΓòÉΓòÉΓòÉ 3.3. Trigraph Sequences ΓòÉΓòÉΓòÉ
-
- Certain characters contained in the C++ character set are not available on all
- keyboards. You can represent these characters in a C++ source program by using
- a combination of keystrokes called a trigraph sequence. Before preprocessing,
- each trigraph sequence in a string or a literal is replaced by the single
- character that it represents. Trigraphs cannot be created using macro
- concatenation. The trigraph sequences are:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé ??= Γöé # Γöé pound sign Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??( Γöé [ Γöé left bracket Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??) Γöé ] Γöé right bracket Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??/ Γöé \ Γöé backslash Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??' Γöé ^ Γöé caret Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??! Γöé Γöé Γöé pipe Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??< Γöé { Γöé left brace Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??> Γöé } Γöé right brace Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ??- Γöé ~ Γöé tilde. Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
-
- ΓòÉΓòÉΓòÉ 3.4. Digraph Sequences ΓòÉΓòÉΓòÉ
-
- If you use the -qdigraph compile option, you can represent unavailable
- characters in a C++ source program by using a combination of two keystrokes
- called a digraph sequence. Digraphs are read as tokens during the preprocessor
- phase. Digraphs can be created using macro concatenation. They are not replaced
- in string literals or in character literals. For example:
-
- char *s = "<%%>"; // stays "<%%>"
-
- switch (c)
- {
- case '<%' : { /* ... /* } // stays '<%'
- case '%>' : { /* ... /* } // stays '%>'
- }
-
- The digraph sequences are:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé %% Γöé # Γöé pound sign Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé < : Γöé [ Γöé left bracket Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé : > Γöé ] Γöé right bracket Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé <% Γöé { Γöé left brace Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé %> Γöé } Γöé right brace Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- For more information on the -qdigraph compiler option, see the "Summary of the
- C[++ ] Compiler/6000 Options" of the Programming Guide
-
-
- ΓòÉΓòÉΓòÉ 3.5. Escape Sequences ΓòÉΓòÉΓòÉ
-
- Escape sequences are primarily used to place nonprintable characters in
- character and string literals. You can use an escape sequence to represent any
- member of the ASCII system character set. For example, an escape sequence can
- be used to place a tab, carriage return, or backspace into a string literal or
- character constant.
-
- An escape sequence consists of a \ (backslash) symbol followed by one of the
- escape sequence characters. The C++ escape sequences are: :dtchd. Escape
- Character Sequence Represented
-
- \a Alert (bell)
-
- \b Backspace
-
- \f Form feed (new page)
-
- \n New-line
-
- \r Carriage return
-
- \t Horizontal tab
-
- \v Vertical tab
-
- \' Single quotation mark
-
- \" Double quotation mark
-
- \? Question mark
-
- \\ Backslash.
-
- You can use the first seven escape sequences, \a through \v, in string literals
- to add the features shown above. You can use the single quotation mark escape
- sequence, \', to place a single quotation mark in a character literal. The
- double quotation mark escape sequence, \", places a double quotation mark in a
- string literal. The question mark escape sequence, \? , places the question
- mark character found in a trigraph in a string literal. The backslash escape
- sequence, \\ , places a backslash character found in an escape sequence in a
- string literal. For example:
-
- cout << "The escape sequence \\n." <<
- endl;
-
- This statement will result in the following output:
-
- The escape sequence \n.
-
- To represent an octal number, use a backslash followed by up to three octal
- digits. The maximum length of an octal escape sequence is three digits.To
- represent a hexadecimal number, use a backslash followed by x followed by any
- number of hexadecimal digits. A hexadecimal escape sequence terminates with
- the first digit that is not a hexadecimal digit; however, the &xcomp. only uses
- the last two digits.
-
- The octal and hexadecimal escape sequences specify the value of the character
- they represent. For example, the character 'a' can be represented by the octal
- escape sequence \141 and the hexadecimal escape sequence\x61 because the value
- of 'a' in ASCII is97. The following program prints the character 'a' four times
- to standard output, and then prints a new line:
-
- #include<iostream.h>
- void main()
- {
- char a,b,c,d,e;
- a='a';
- b=97;
- c='\141';
- d='\x61';
- e='\n';
- cout << a << b << c <<
- d << e;
- }
-
-
- ΓòÉΓòÉΓòÉ 3.6. Comments ΓòÉΓòÉΓòÉ
-
- There are two types of comments in C++. Single line comments begin with two
- adjacent slashes // and terminate at the end of the line they appear on. The /*
- characters begin a single or multiple line comment that terminates with the */
- characters. Because comments cannot be nested, the comment characters // , /*
- and */ have no meaning within a single line comment. Similarly, the comment
- characters // and /* have no meaning within a comment beginning with /*.
-
- In the following example, all characters recognized by C++ as comments are
- highlighted in boldface type:
-
- 1 // A function with nested comments
- 2
- 3 void f()
- 4 {
- 5 int num;
- 6 char letter;
- 7 /*
- 8 num = 55; // initialize num
- 9 letter = 'A'; */
- 10 */
- 11 // The previous line causes an error
- 12 }
-
- When the function f() is read, the &xcomp. &xcompos2. reads lines 7 through 9
- as a comment, but line 10 is a C++ statement and generates a compiler error.
- The comment on line 11 is a valid single-line comment.
-
-
- ΓòÉΓòÉΓòÉ 3.7. Identifiers ΓòÉΓòÉΓòÉ
-
- Identifiers provide names for the C++ elements. An identifier is made up of an
- arbitrary number of digits and letters but must begin with a letter. The _
- (underscore) character is viewed as a letter. There is no set maximum length
- for an identifier in C++.
-
- C++ distinguishes between the uppercase and lowercase letters in an identifier.
- Thus, the identifiers TRUE, True, and true all represent different names.
-
- C++ reserves identifiers containing _ _ (double underscore) and beginning with
- _ (single underscore).
-
- Identifiers can only contain the $ character in extended mode. See
- "Interlanguage Calling Conventions" in the Programming Guide for more details.
-
-
- ΓòÉΓòÉΓòÉ 3.8. Keywords ΓòÉΓòÉΓòÉ
-
- Keywords are identifiers reserved by C++ for special uses. Only the lowercase
- versions are reserved. For example, Do, containing an uppercase letterD, is not
- a keyword in C++. You can use keywords as macro names. The following is a list
- of C++ keywords.
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé asm Γöé continue Γöé float Γöé new Γöé signed Γöé try Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé auto Γöé default Γöé for Γöé operator Γöé sizeof Γöé typedef Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé break Γöé delete Γöé friend Γöé private Γöé static Γöé union Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé case Γöé do Γöé goto Γöé pro- Γöé struct Γöé unsignedΓöé
- Γöé Γöé Γöé Γöé tected Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé catch Γöé double Γöé if Γöé public Γöé switch Γöé virtual Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé char Γöé else Γöé inline Γöé register Γöé template Γöé void Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé class Γöé enum Γöé int Γöé return Γöé this Γöé vola- Γöé
- Γöé Γöé Γöé Γöé Γöé Γöé tile Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé const Γöé extern Γöé long Γöé short Γöé throw Γöé while Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- If you use the -qdigraph compile option, you can represent unavailable
- characters in a C++ source program by using the following keywords:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé KEYWORD Γöé Symbol Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé bitand Γöé & Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé and Γöé && Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé bitor Γöé Γöé Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé or Γöé ΓöéΓöé Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé xor Γöé ^ Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé compl Γöé ~ Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé and_eq Γöé &= Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé or_eq Γöé Γöé= Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé xor_eq Γöé ^= Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé not Γöé ! Γöé Γöé Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé not_eq Γöé != Γöé Γöé Γöé Γöé Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- These keywords are only reserved if you use the -qdigraph option. For more
- information on the -qdigraph compiler option, see the "Summary of the C[++ ]
- Compiler/6000 Options" of the Programming Guide for IBM AIX XL C++
- Compiler/6000 Version 1.1.1.
-
-
- ΓòÉΓòÉΓòÉ 3.9. Literals ΓòÉΓòÉΓòÉ
-
- C++ contains the following types of literals (also called constants):
-
- o Integer constants
-
- o Character constants
-
- o Floating constants
-
- o String literals.
-
-
- ΓòÉΓòÉΓòÉ 3.9.1. Integer Constants ΓòÉΓòÉΓòÉ
-
- You can use integer constants to represent decimal, octal, and hexadecimal
- values.
-
- A decimal constant is composed of a sequence of the digits, 0 (zero) through 9,
- beginning with a nonzero digit, as well as optional suffixes u and l. For
- example:
-
- 485976
- 433132211
- 20
- 5
-
- An octal constant is composed of a sequence of the digits, 0 (zero) through 7,
- beginning with a 0 (zero). For example:
-
- 0
- 0125
- 034673
- 03245
-
- A hexadecimal constant begins with the 0 (zero) digit followed by either x or
- X, and it can contain any combination of the digits 0 (zero) through 9 and the
- letters a through f or A through F. The lowercase and uppercase letters are
- equivalent in a hexadecimal constant. For example:
-
- 0x3b24
- 0XF96
- 0x21
- 0x3AA
- 0X29b
- 0X3bD
-
- The data type is determined by the form, value, and suffix of the integer
- constant. The following lists the integer constants and shows the possible data
- types for each constant. The smallest data type in the list that can represent
- the constant value is assigned to the constant. Constant Data Type
-
- unsuffixed decimal int, long int, unsigned long int
-
- unsuffixed octal int, long int, unsigned long int
-
- unsuffixed hexadecimal int, long int, unsigned long int
-
- suffixed by u or U unsigned int, unsigned long int
-
- suffixed by l or L long int, unsigned long int
-
- suffixed by both
-
- u or U and l or L unsigned long int
-
- A + (plus) or - (minus) symbol preceding an integer constant is treated as a
- unary operator rather than as a part of the integer constant value.
-
-
- ΓòÉΓòÉΓòÉ 3.9.2. Character Constants ΓòÉΓòÉΓòÉ
-
- A character constant contains one or more characters or an escape sequence
- enclosed in single quotation marks. The following are all character constants:
-
- 'X' '\'' '0'
-
- '(' 'x' '\n'
-
- '7' '\117' 'n'
-
- Character constants composed of single characters have type char. The value of
- a single character constant is the numerical value of the character in the
- ASCII character set.
-
- Character constants composed of multiple characters have type int. The value of
- a multiple character constant is implementation-dependent.
-
- Character constants with the prefix L, have type wchar_t (wide character). The
- wide character type is implementation-dependent and is defined in the C
- standard header file <stddef.h>, described in the IBM AIX for RISC System/6000
- Files Reference.
-
- Character constants with the prefix L, have type wchar_t (wide character). The
- wide character type is implementation-dependent and is defined in the C
- standard header file <stddef.h>.
-
- .* From heading: "Escape Sequences" Escape sequences can be used to represent
- specific nongraphic characters including \ (backslash ), ? (question mark), '
- (single quotation mark), and " (double quotation mark).
-
-
- ΓòÉΓòÉΓòÉ 3.9.3. Floating Constants ΓòÉΓòÉΓòÉ
-
- A floating constant consists of an integer part, a decimal point, a fractional
- part, an exponent part (an e or E and an optionally signed integer), and an
- optional suffix. Both the integral and fractional parts are made up of decimal
- digits. You can omit either the integral part or the fractional part but not
- both. You can omit either the decimal point or the exponent part but not both.
- Unless specified by a suffix, floating constants have type double. The suffixf
- or F indicates a type of float. The suffix l orL indicates a type of long
- double. The following table shows the three possible data types for floating
- constants:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé Floating Constant Γöé Data Type Γöé Value Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé .5E1 Γöé double Γöé 5.0 Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé 50e-1f Γöé float Γöé 5.0 Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé 5.0L Γöé long double Γöé 5.0 Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
-
- ΓòÉΓòÉΓòÉ 3.9.4. String Literals ΓòÉΓòÉΓòÉ
-
- A string literal contains a sequence of characters enclosed in double quotation
- marks. It has the data type array of char and has static storage duration. A
- string literal prefixed by the letter L is a wide character string literal. It
- has the data type array of wchar_t. This data type is implementation-dependent
- and is defined in the C standard header file <stddef.h>.
-
- For example, L"longstring" is a wide character string literal.
-
- To continue a string literal on the next line, place a \ (backslash) at the end
- of the line. The backslash is read as a line continuation symbol rather than as
- a character in the string literal. A carriage return must immediately follow
- this backslash. In the following example, the string literal second causes a
- compile-time error.
-
- char *first = "This string continues onto the next\
- line, where it ends."; // compiles successfully.
- char *second = "The comment makes the \ // continuation
- symbol
- invisible to the compiler."; // compilation error.
-
- Another way to continue a string literal is to have two or more adjacent
- strings. Consecutive string literals are concatenated to produce a single
- string literal. Characters in concatenated strings remain distinct. For
- example, the strings "\xab" and "3" are concatenated to form "\xab3". However,
- the characters \xab and 3 remain distinct and are not merged to form the
- hexadecimal character \xab3. You cannot concatenate an ordinary string literal
- with a wide string literal. For example:
-
- "hello " "there" // is equivalent to "hello there"
- "hello " L"there" // is illegal
- "hello" "there" // is equivalent to "hellothere"
-
- Following any concatenation, \0 (a zero of type char) is appended at the end of
- each string. C++ programs find the end of a string by scanning for this value.
- For a wide character string literal, \0 of type wchar_t is appended. For
- example:
-
- char *first = "Hello "; // stored as "Hello \0"
- char *second = "there"; // stored as "there\0"
- char *third = "Hello " "there"; // stored as "Hello
- there\0"
-
- Within a string literal, you must use the escape sequence \" to represent a
- double quotation mark. Use the \n escape sequence to represent the new line
- character as part of a string and the \\ to represent the backslash character.
- For example:
-
- #include <iostream.h>
- void main ()
- {
- char *s ="Hi there! \n";
- cout << s;
- char *p = "The backslash character \\.";
- cout << p << endl;
- char *q = "The double quotation mark \".\n";
- cout << q ;
- }
-
- This program produces the following output:
-
- Hi there!
- The backslash character \.
- The double quotation mark ".
-
-
- ΓòÉΓòÉΓòÉ 3.10. Related Information ΓòÉΓòÉΓòÉ
-
- "Type Specifiers"
-
-
- ΓòÉΓòÉΓòÉ 4. Chapter 4. Expressions and Operators ΓòÉΓòÉΓòÉ
-
- This chapter describes C++ expressions and operators. It begins with general
- descriptions of the following topics:
-
- o Expressions
- o Operands
- o Objects
- o lvalues
-
- These general descriptions are followed by descriptions of the following
- specific types of expressions:
-
- o Primary expressions
-
- o Constant expressions
-
- o Postfix expressions
-
- o Cast expressions
-
- o Unary expressions
-
- o Binary expressions.
-
- These descriptions begin with a list of the operators that are used in that
- specific type of expression.
-
- You can also return to the table of contents.
-
-
- ΓòÉΓòÉΓòÉ 4.1. Expressions ΓòÉΓòÉΓòÉ
-
- Expressions are sequences of operators, operands, and punctuators that specify
- a computation. The evaluation of expressions is based on the operators that the
- expressions contain and the context in which they are used. An expression can
- result in an lvalue, rvalue, or no value, and can produce side effects in each
- case.
-
- C++ operators can be defined to behave differently when applied to operands of
- class type. This is calledoperator overloading. See "Overloading Operators" for
- more details.
-
- You cannot change the behaviour of operators when they are applied to built-in
- types. The syntax specifications as outlined in this chapter are still
- applicable to built-in types. This chapter describes the behavior of operators
- that are not overloaded.
-
-
- ΓòÉΓòÉΓòÉ 4.1.1. Grouping and Evaluating Expressions ΓòÉΓòÉΓòÉ
-
- Two operator characteristics determine how operands group with operators:
- precedence and associativity. Precedence is a priority system for grouping
- different types of operators with their operands. Associativity provides a
- left-to-right or right-to-left order for grouping operands to operators that
- have the same precedence. You can explicitly state the grouping of operands
- with operators by using parentheses.
-
- Consider the expression:
-
- a + b * c / d
-
- Here is the same expression with parentheses to show how the operands are
- grouped with operators:
-
- a + ((b * c) / d)
-
- The + is evaluated last because it has lower precedence than * or /. The * is
- evaluated before the / because of associativity.
-
- The following table lists the C++ operators in their order of precedence and
- shows the direction of associativity for each operator. The operators are
- listed in order of precedence. The primary scope operator has the highest
- precedence, and the comma operator has the lowest.
-
-
- ΓòÉΓòÉΓòÉ 4.1.2. Operator Precedence and Associativity ΓòÉΓòÉΓòÉ
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé Operator Type Γöé Associativity Γöé Operators Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Primary Γöé left to right Γöé : : Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Postfix Γöé left to right Γöé () [] . -> Γö╝+ - - Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Unary Γöé right to left Γöé Γö╝+ - - - + ! ~ & * Γöé
- Γöé Γöé Γöé sizeof Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Γöé Γöé new delete Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Cast Γöé left to right Γöé (typename) Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Pointer to Member Γöé left to right Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Multiplicative Γöé left to right Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Additive Γöé left to right Γöé + - Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Bitwise Shift Γöé left to right Γöé << >> Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Relational Γöé left to right Γöé < > <= >= Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Equality Γöé left to right Γöé = = != Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Bitwise Logical AND Γöé left to right Γöé & Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Bitwise Exclusive Γöé left to right Γöé ^ Γöé
- Γöé OR Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Bitwise Inclusive Γöé left to right Γöé Γöé Γöé
- Γöé OR Γöé Γöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Logical AND Γöé left to right Γöé && Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Logical OR Γöé left to right Γöé ΓöéΓöé Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Conditional Γöé right to left Γöé ? : Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Assignment Γöé right to left Γöé = Γö╝= -= *= /= <<= Γöé
- Γöé Γöé Γöé >>= %= &= ^= Γöé= Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé Comma Γöé left to right Γöé , Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- C++ does not specify the order of evaluation for function arguments or for the
- operands of binary operators. Exceptions are noted in the following section.
-
- The following are examples of ambiguous expressions:
-
- :id='51V01296'.
- z = (x * ++y) / f(y);
-
- ++y andf(y) may not be evaluated in the same order by all C++ compilers.
-
- f(++i, x[i]);
-
- ++i andx[i] may not be evaluated in the same order by all C++ compilers.
-
-
- ΓòÉΓòÉΓòÉ 4.1.3. Exceptions ΓòÉΓòÉΓòÉ
-
- C++ does not specify the order that operands are grouped with operators in an
- expression that contains more than one instance of an operator that has both
- associative and commutative properties. The &xcomp. can rearrange operands in
- such an expression. You can use parentheses to guarantee the order of grouping
- within the expression. The operators that have the same associative and
- commutative properties are: *, +, &, |, and ^.
-
- The order of evaluation for the operands of the && (logical AND ) and the | |
- (logical OR ) operators is always left to right. If the operand on the left
- side of the && operator evaluates to zero, the operator on the right side is
- not evaluated. If the operand on the left side of a | | operator evaluates to a
- nonzero value, the operator on the right side is not evaluated.
-
- The parentheses in the following expressions explicitly show how C++ groups
- operands and operators:
-
- total = (4 + (5 * 3));
- total = (((8 * 5) / 10) / 3);
- total = (10 + (5 / 3));
-
- Because C++ does not specify the order of grouping operands with operators that
- are both associative and commutative, a compiler can group the operands and
- operators of the expression:
-
- total = price + prov_tax + city_tax;
-
- in the following ways:
-
- total = (price + (prov_tax + city_tax));
- total = ((price + prov_tax) + city_tax);
- total = ((price + city_tax) + prov_tax);
-
- If the values in this expression are integers, the grouping of operands and
- operators does not affect the result. Because intermediate values are rounded,
- different groupings of floating-point operators give different results.
-
- However, in certain expressions, the grouping of operands and operators can
- affect the result. In the following expression, each function call may be
- modifying the same variables:
-
- a = b() + c() + d();
-
- If the expression contains operators that are both associative and commutative
- and the order of grouping operands with operators can affect the result of the
- expression, you can break the expression into several expressions. For example,
- the following expressions can replace the previous expression if the called
- functions do not produce any side effects affecting the variablea.
-
- a = b();
- a += c();
- a += d();
-
- Integer overflows are ignored. Division by zero and floating-point exceptions
- are implementation specific. For more details on generating warning messages
- for division by constant zero, see the -qinfo compiler option described in
- "Summary of the C[++ ] Compiler/6000 Options" of the Programming Guide.
-
-
- ΓòÉΓòÉΓòÉ 4.2. Operands ΓòÉΓòÉΓòÉ
-
- Most expressions can contain several different, but related, types of operands.
- The following list shows some of the different kinds of operands:
-
- o Integral: objects having type char, unsigned char, signed char, short, int,
- long, unsigned short, unsigned int, or unsigned long
-
- o Enumeration:Objects having an enumeration type
-
- o Arithmetic: Integral objects and objects having type float, double, or long
- double
-
- o Scalar: Arithmetic objects, references, and pointers to objects of any type
-
- o Arrays: Arrays
-
- o Classes: Unions, structures and classes.
-
- Many C++ operators cause implicit conversions from one data type to another.
- Implicit type conversions are described in "Type Conversions"
-
- For further details on data types, see "Type Specifiers"
-
-
- ΓòÉΓòÉΓòÉ 4.3. Objects ΓòÉΓòÉΓòÉ
-
- An object is a region of storage that contains a value or group of values. Each
- value can be accessed using its identifier or a more complex expression that
- refers to the object. In addition, each object has a unique data type. Both the
- identifier and data type of an object are established in the object
- declaration.
-
- The data type of an object determines the initial storage allocation for that
- object and the interpretation of the values during subsequent access. It is
- also used in any type-checking operations.
-
- C++ has built-in or standard data types and user-defined data types. Standard
- data types include signed and unsigned integers, floating-point numbers, and
- characters. User-defined types include enumerations, structures, unions, and
- classes.
-
- An instance of a class type is commonly called a class object. The individual
- class members are also called objects. The set of all member objects comprises
- a class object.
-
-
- ΓòÉΓòÉΓòÉ 4.4. lvalues ΓòÉΓòÉΓòÉ
-
- An lvalue is an expression that represents an object. A modifiable lvalue is
- an expression representing an object that can be changed. If an lvalue is
- modifiable, it can be the left operand in an assignment expression. For
- example, array objects, array names, function names, and const objects are not
- modifiable lvalues, but a static int object is.
-
- All assignment operators evaluate their right operand and assign that value to
- their left operand. The left operand must be a modifiable lvalue or a reference
- to a modifiable object. The increment and the decrement operators also require
- a modifiable lvalue as an operand.
-
- The address operator requires an lvalue, a function name, or a qualified class
- name as an operand. The lvalue does not have to be modifiable. The following
- example shows two expressions and their corresponding lvalues. :id='162TO148d'.
- Expression lvalue
-
- :id='162TO148e'.
- x = 42; x
- *ptr = newvalue; *ptr
-
-
- ΓòÉΓòÉΓòÉ 4.5. Primary Expressions ΓòÉΓòÉΓòÉ
-
- Primary expressions are literals, names, and names qualified by the :: (scope)
- operator. The syntax of the primary expression is:
-
- primary-expression:
- literal
- this
- ( expression )
- :: identifier
- :: qualified-name
- :: operator-function-name
- name
-
- A literal is one of the following:
-
- o integer-constant
-
- o character-constant
-
- o floating-constant
-
- o string-literal.
-
- .* From heading: "The this Pointer" this is a keyword used within the body of
- nonstatic member functions to name a pointer to the object for which the
- function was invoked.
-
- A parenthesized expression has the same type and value as the expression within
- the parentheses.
-
- The type of the primary expression represented by the :: (scope) operator
- followed by an identifier, qualified-name, or operator-function-name is
- specified by the declaration of the identifier, name, or
- operator-function-name.
-
- A name is a primary expression that can appear after the . (dot) and ->
- (arrow) operators. The syntax for a name is:
-
- name:
- identifier
- qualified-name
- operator-function-name
- conversion-function-name
- ~ class-name
- qualified-name:
- qualified-class-name :: name
-
- literal:
- integer-constant
- character-constant
- floating-constant
- string-literal
-
- A qualified-name is a qualified-class-name followed by the :: (scope) operator
- followed by a name that is either a member of the class or a base class of the
- class.
-
- An operator-function-name is an overloaded operator.
-
- A conversion-function-name is a conversion member function.
-
- A class-name preceded by ~ indicates a destructor for the class class-name.
-
-
- ΓòÉΓòÉΓòÉ 4.5.1. Scope Operator ΓòÉΓòÉΓòÉ
-
- The :: (scope) operator is used to qualify hidden names so that you can still
- use them. You can use the unary scope operator if a file scope name is hidden
- by an explicit declaration of the same name in a block or class. You can use
- the hidden file scope name by qualifying it with the scope operator. For
- example:
-
- int i = 10;
- int f(int i)
- {
- return i ? i : :
- :i; // return global i if local i
- is zero
- }
-
- You can also use the class scope operator to qualify class names or class
- member names. If a class member name is hidden, you can use it by qualifying it
- with its class name and the class scope operator. Whenever a name is followed
- by a :: (scope) operator, the name is interpreted as a class name. Class names
- hidden by local variable names can be retrieved when followed by :: (scope)
- operator. In the following example, the declaration of the variable X hides the
- class type X but you can still use the static class member count by qualifying
- it with the class type X and the scope operator.
-
- #include <iostream.h>
- class X
- {
- public:
- static int count;
- };
- int X::count = 10; // define static data member
- void main ()
- {
- int X = 0; // hides class type X
- cout << X::count << endl; // use static
- member of class X
- }
-
- The scope operator is also discussed in "Class Names" and in "Scope of Class
- Names"
-
-
- ΓòÉΓòÉΓòÉ 4.5.2. Parenthesized Expressions ΓòÉΓòÉΓòÉ
-
- You can use parentheses to explicitly state how operands group with operators.
- The following expression does not contain any parentheses that group operands
- and operators. The parentheses surrounding weight and postcode form a function
- call. Notice how the operands and operators are grouped in this expression :
- Expression without Parentheses
-
- -discount * item + handling(weight, zipcode) > .10 * item
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- The following expression is similar, but contains parentheses that change the
- way the operands and operators are grouped:
- Expression with Parentheses
-
- :id='162TO1494'.
- (-discount * (item + handling(weight, zipcode))) > (.10
- * item)
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- In an expression that contains operators that are both associative and
- commutative, you can use parentheses to specify the grouping of operands with
- operators. The parentheses in the following expression guarantee the order of
- grouping:
-
- :id='51V012d2'.
- x = f + (g + h);
-
-
- ΓòÉΓòÉΓòÉ 4.6. Constant Expressions ΓòÉΓòÉΓòÉ
-
- A constant-expression is an expression that evaluates to an integral constant.
- A constant-expression can contain the following:
-
- o sizeof expressions
-
- o literals, enumerators, and values of integral types declared constant and
- initialized with constant expressions.
-
- The syntax for a constant expression is:
-
- constant-expression:
- conditional-expression
-
- Only type conversions to integral types are allowed in constant expressions.
- Functions, class objects, pointers, and references are not allowed unless they
- occur in sizeof expressions. Comma operators and assignment operators cannot
- appear in constant expressions.
-
- You can use a constant expression anywhere that you can use a constant. For
- example, you can use a constant expression as an array bound, in case
- expressions found in switch statements, as an initializer of an enumeration
- constant, as the size of a bit field, and as a template argument.
-
-
- ΓòÉΓòÉΓòÉ 4.7. Postfix Expressions ΓòÉΓòÉΓòÉ
-
- Seven operators are used in postfix expressions:
-
- o Function call ( )
-
- o Function style cast ( )
-
- o Array subscript [ ]
-
- o Dot .
-
- o Arrow ->_
-
- o Postfix increment ++
-
- o Postfix decrement --
-
- Postfix expressions group left-to-right.The syntax is:
-
- postfix-expression:
- primary-expression
- postfix-expression
- ([expression-list]
- )
- simple-type-name
- ([expression-list]
- )
- postfix-expression [
- expression
- ]
- postfix-expression . name
- postfix-expression -> name
- postfix-expression ++
- postfix-expression --
-
- The syntax for an expression-list is:
-
- expression-list:
- assignment-expression
- expression-list ,
- assignment-expression
-
-
- ΓòÉΓòÉΓòÉ 4.7.1. Function Call ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- postfix-expression (
- [
- expression-list ] )
-
- A function call is a postfix expression or a simple type name followed by a
- parenthesized argument list. The argument list can contain any number of
- expressions separated by commas. It can also be empty. The number of actual
- arguments in a function call expression list must equal the number of formal
- arguments in the argument list of the function declaration.
-
- The following are examples of function calls:
-
- :id='51V012d6'.
- stub()
- overdue(account, date, amount)
- notify(name, date + 5)
- report(error, time, date, ++num)
-
- The actual arguments are evaluated, and each formal argument is assigned the
- value of the corresponding actual argument. Assigning a value to a formal
- argument changes the value within the function but has no effect on the actual
- argument unless the formal argument is a reference to an object.
-
- The type of a function call expression is the return type of the function. The
- return value is determined by the return statement in the function definition.
- The result of a function call is an lvalue only if the function returns a
- reference. A function can call itself.
-
- Arguments that are arrays and functions are converted to pointers before they
- are passed to a function.
-
- The data types of the actual arguments of the calling function are compared
- with the data types of the formal arguments that the called function expects.
- The actual arguments are converted to the types of the formal arguments because
- the declaration is visible at the point where the function is called.
-
- For example, the declaration of func is a prototype. When functionfunc is
- called, the actual argumentf is converted to a double, and the actual argument
- c is converted to an int.
-
- :id='218TO1866'.
- char* func (double d, int i);
- .
- .
- .
- void main()
- {
- float f;
- char c;
- func(f, c) // f is a double, c is an int
- }
-
- C++ does not define the order in which the &xcomp. evaluates parameters.
-
- For further details on functions and argument passing, see "Functions" For
- further details on overloading the function call operator, see "Function Call"
- in the section "Special Overloaded Operators"
-
-
- ΓòÉΓòÉΓòÉ 4.7.2. Function Style Cast ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- simple-type-name (
- [
- expression-list ] )
-
- Function style casts are described in "Cast Expressions"
-
-
- ΓòÉΓòÉΓòÉ 4.7.3. Array Subscript ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- postfix-expression [
- expression
- ]
-
- A postfix expression followed by an expression in [ ] (square brackets) refers
- to an element of an array. One expression must be a pointer value, and the
- other must be an integral type. The result of an array subscript is an lvalue.
-
- The first element of an array has the subscript zero. Thus, the
- expressioncode[10] refers to the 11th element of the array code.
-
- By definition, the expression:
-
- *((exp1) + (exp2))
-
- is identical to the expression:
-
- exp1[exp2]
-
- which is also identical to:
-
- exp2[exp1]
-
- For further details, see "Arrays"
-
-
- ΓòÉΓòÉΓòÉ 4.7.4. Dot ΓòÉΓòÉΓòÉ
-
- The . (dot) operator is a class access member operator that is used to access
- class members using a class object. The syntax is:
-
- postfix-expression . name
-
- A postfix expression, followed by a operator, followed by a name, designates a
- member of a class object. The postfix expression must be a class object. Note
- that class objects can be of type class, struct, or union. The name must be a
- member of that class object.
-
- The value of the expression is the value of the selected member. If the postfix
- expression and the name are lvalues, the expression value is also an lvalue.
-
- For further details on class members, see "Class Members and Friends"
-
-
- ΓòÉΓòÉΓòÉ 4.7.5. Arrow ΓòÉΓòÉΓòÉ
-
- (arrow).
-
- The -> (arrow) operator is a class access member operator that is used to
- access class members using a pointer. The syntax is:
-
- postfix-expression -> name
-
- A postfix expression, followed by an -> (arrow) operator, followed by a name,
- designates a member of the object to which the pointer points. The postfix
- expression must be a pointer to a class object. Note that class objects can be
- of type class, struct, or union. The name must be a member of that class
- object.
-
- The value of the expression is the value of the selected member. If the name is
- an lvalue, the expression value is also an lvalue.
-
- For further details on class members, see "Class Members and Friends"
-
-
- ΓòÉΓòÉΓòÉ 4.7.6. Postfix Increment ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the ++ (postfix increment) operator is:
-
- postfix-expression ++
-
- A postfix expression followed by ++ (increment) operator is used to increment
- the operand. The postfix expression is the operand, which must be a modifiable
- lvalue of arithmetic or pointer type.
-
- The value of the expression is the value of the postfix expression before the
- increment is applied. After evaluation, the operand is incremented by 1. The
- type of the result is the same as the type of the operand, but it is not an
- lvalue.
-
- The postfix increment, prefix increment, and unary plus are distinct operators.
- For further details, see also "Prefix Increment" and "Unary Plus"
-
-
- ΓòÉΓòÉΓòÉ 4.7.7. Postfix Decrement ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the - - (postfix decrement) operator
- is:
-
- postfix-expression --
-
- A postfix expression followed by the - - (decrement) operator is used to
- decrement the operand. The postfix decrement operator follows the same rules as
- the postfix increment operator except that the operand is decremented by 1.
-
- The postfix decrement, prefix decrement, and unary minus are distinct
- operators. For further details, see also "Prefix Decrement" and "Unary Minus"
-
-
- ΓòÉΓòÉΓòÉ 4.8. Cast Expressions ΓòÉΓòÉΓòÉ
-
- The cast operator is used for explicit type conversions. The syntax for a cast
- expressions is:
-
- cast-expression:
- unary-expression
- ( typename ) cast-expression
-
- The ( ) (cast) operator converts the value of the cast-expression to the
- specified type. If the cast-expression has class type, the type-name can be any
- type for which the class has a user-defined conversion function.
-
- The result of a cast is not an lvalue unless the cast is to a reference type.
- When you cast to a reference type, no user-defined conversions are performed
- and the result is an lvalue.
-
- There are two types of casts that take one argument:
-
- o C-style casts, with the format (X)a
-
- o function-style casts with one arguments, such as X(a).
-
- Both types of casts convert the argument a to the type X.
-
- A function-style cast with no arguments, such as X(), creates a temporary
- object of type X. If X is a class with constructors, the default constructor X:
- is called.
-
- A function-style cast with more than one argument, such as X(a,b), creates a
- temporary object of type X. X must be a class with a constructor that takes two
- arguments of types compatible with the types of a and b. This constructor is
- called with a and b as arguments.
-
- For details on implicit conversions using constructors, see "Conversion by
- Constructor"
-
- Explicit conversions can also be done using conversion functions. For further
- details, see "Conversion Functions "
-
- Implicit conversions using standard types are described in "Type Conversions"
-
-
- ΓòÉΓòÉΓòÉ 4.9. Unary Expressions ΓòÉΓòÉΓòÉ
-
- A unary expression contains one operand of arithmetic or pointer type and a
- unary operator. All unary operators have the same precedence and have right to
- left associativity.
-
- The operators used in unary expressions are:
-
- o Prefix increment
-
- o Prefix decrement
-
- o Unary plus
-
- o Unary minus
-
- o Logical negation
-
- o Bitwise negation
-
- o Address
-
- o Indirection
-
- o sizeof
-
- o new
-
- o delete and delete[]
-
- o throw .
-
- The syntax for expressions containing unary operators is:
-
- :id='CPLRexpUnarSynt'.
- unary-expression:
- postfix-expression
- ++ unary-expression
- -- unary-expression
- unary-operator cast-expression
- sizeof unary-expression
- sizeof ( type-name
- )
- allocation-expression
- deallocation-expression
- throw-expression
-
- The usual arithmetic conversions are performed on the operands of most unary
- expressions. For more details, see "Arithmetic Conversions"
-
-
- ΓòÉΓòÉΓòÉ 4.9.1. Prefix Increment ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the ++ (prefix increment) operator is:
-
- ++ unary-expression
-
- The ++ (increment) operator followed by a unary expression is used to increment
- the operand. The unary expression is the operand, which must be a modifiable
- lvalue of arithmetic or pointer type.
-
- Before evaluation, the operand is incremented by 1.The value of the expression
- is the value of the prefix expression after the increment is applied.
-
- The type of the result is the same as the type of the operand and is also a
- modifiable lvalue.
-
- See also "Postfix Increment" and "Unary Plus"
-
-
- ΓòÉΓòÉΓòÉ 4.9.2. Prefix Decrement ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the - - (prefix decrement) operator is:
-
- -- unary-expression
-
- The - - (decrement) operator followed by an unary expression is used to
- decrement the operand.
-
- The prefix decrement operator follows the same rules as the prefix increment
- operator, except that the operand is decremented by 1.
-
- See also "Postfix Decrement" and "Unary Minus"
-
-
- ΓòÉΓòÉΓòÉ 4.9.3. Unary Plus ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the + (unary plus) operator is:
-
- +
- cast-expression
-
- The + (unary plus) operator maintains the value of the operand, which must have
- arithmetic or pointer type.
-
- Integral promotions are performed on the operand. For more details, see
- "Integral Promotions"
-
- The type of the result is the promoted type of the operand.The result is not an
- lvalue.
-
-
- ΓòÉΓòÉΓòÉ 4.9.4. Unary Minus ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the - (unary minus) operator is:
-
- -
- cast-expression
-
- The - (unary minus) operator negates the value of the operand, which must have
- arithmetic type. Integral promotions are performed on the operand. For more
- details, see "Integral Promotions"
-
- The result of applying the unary minus operator to a signed operand is the
- negation of the operand. The result is not an lvalue. The negative of an
- unsigned value is determined by subtracting its value from 2[n], where n is the
- number of bits in the promoted operand.
-
-
- ΓòÉΓòÉΓòÉ 4.9.5. Logical Negation ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the ! (logical negation) operator is:
-
- !
- cast-expression
-
- The ! (logical negation) operator yields a 1 (true) if its operand evaluates to
- a zero (false). If the value of its operand is nonzero, the result of the
- operation is zero.
-
- The operand must have an arithmetic or pointer type. The type of the result is
- int and is not an lvalue. For operands of integral type, integral promotions
- are performed on the operand. For more details, see "Integral Promotions"
-
-
- ΓòÉΓòÉΓòÉ 4.9.6. Bitwise Negation ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the ~ (bitwise negation) operator is:
-
- ~
- cast-expression
-
- The ~ (bitwise negation) operator yields the ones complement of the operand. In
- the binary representation of the result, every bit has the opposite value of
- the same bit in the operand. The operand must have an integral type. The result
- is not an lvalue.
-
- Integral promotions are performed on the operand. For more details, see
- "Integral Promotions"
-
-
- ΓòÉΓòÉΓòÉ 4.9.7. Address ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the & (address) operator is:
-
- &
- cast-expression
-
- The & (address) operator yields a pointer to the operand. The operand must be
- an lvalue, a function, or a qualified name.If the variableptr is defined as a
- pointer to an int, and y as an int, the following expression assigns the
- address of the variable y to the pointer ptr:
-
- ptr = &y;
-
- If the operand is an lvalue or function, the resulting type is a pointer to the
- expression type. For example, if the type of the expression is integer, then
- the result is a pointer to an object integer type.
-
- If the operand is a qualified name, and the member is not static, the result is
- a pointer to a member of class and has the same type as the member.
-
- The & operator can only be used with overloaded functions in an initialization
- or assignment and where the left side uniquely determines which version of the
- overloaded function is used.
-
-
- ΓòÉΓòÉΓòÉ 4.9.8. Indirection ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the * (indirection) operator is:
-
- *
- cast-expression
-
- The operand must be a pointer type. The * (indirection) operator determines the
- value referred to by the operand. The operand cannot be a pointer to void.
-
- The result is an lvalue that refers to the object that the expression points
- to. The type of the pointer determines the type of the result. For example, if
- the operand is a pointer to an int, the result also has the int type.
-
- If the variable ptr is defined as a pointer to an int, and y as an int, the
- following expressions cause the value 3 to be assigned to the variable y:
-
- ptr = &y;
- *ptr = 3;
-
- See "Pointers" for more details on indirection.
-
-
- ΓòÉΓòÉΓòÉ 4.9.9. sizeof ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the sizeof operator is:
-
- sizeof
- unary-expression
- sizeof (
- type-name
- )
-
- The sizeof operator yields the size, in bytes, of the operand. The operand can
- be either an expression or a parenthesized type name. If the operand is an
- expression, the expression is not evaluated.
-
- The sizeof operator cannot be applied to a function, a bit field, an undefined
- class, the type void, or an array with unspecified dimensions, but it can be
- applied to a pointer to a function. Types may not be defined in a sizeof
- expression. The result of a sizeof expression depends on the type it is
- applied to:
-
- o When the sizeof operator is applied to an array, the result is the total
- number of bytes in the array. For example, in an array with 10 elements, the
- size is equal to 10 times the size of a single element.
-
- o When the sizeof operator is applied to a class, the result is always nonzero
- and is equal to the number of bytes in an object of that class including any
- padding required for placing class objects in an array.
-
- o When the sizeof operator is applied to a reference, the result is the size of
- the referenced object.
-
- The result of the sizeof operator is a constant of type size_t, which is an
- unsigned integral type defined in the standard header file <stddef.h>.
-
-
- ΓòÉΓòÉΓòÉ 4.9.10. new ΓòÉΓòÉΓòÉ
-
- The new operator provides dynamic storage allocation. The syntax for an
- allocation expression containing the new operator is:
-
- allocation-expression:
- [::]
- new
- [placement] new-type-name
- [new-initializer]
- [::]
- new
- [placement] (
- type-name
- )[new-initializer]
- placement:
- (
- expression-list
- )
- new-type-name:
- type-specifier-list
- [new-declarator]
- new-declarator:
- *[cv-qualifier-list]
- [new-declarator]
- complete-class-name :: *
- [cv-qualifier-list]
- [new-declarator]
- [new-declarator]
- [
- expression ]
- new-initializer:
- ([expression-list]
- )
-
- An allocation expression containing the new operator is used to find storage in
- free store for the object being created. The operator new returns a pointer to
- the object and can be used to initialize the object. If the object is an
- array, a pointer to the initial element is returned. A pointer set to 0 by new
- indicates a failure to allocate memory as specified. You can use the routine
- set_new_handler to change the default behaviour of new. See the Programming
- Guide for more details.
-
- You cannot use the new operator to allocate function types, void, and
- incomplete class types because these are not object types. However, you can
- allocate pointers to functions with the new operator. You cannot create a
- reference with the new operator.
-
- When the object being created is an array, only the first dimension can be a
- general expression. All subsequent dimensions must be constant expressions. The
- first dimension can be a general expression even when the type-name is used.
- You can create an array object with the new operator without specifying a size.
- In this case, a pointer to a unique object is returned.
-
- An object created with new exists until the delete or delete[] operator is
- called to deallocate the object's memory, or until program termination.
-
- If parentheses are used within a new-type-name, parentheses should also
- surround the new-type-name to prevent syntax errors. In the following example,
- storage is allocated for an array of pointers to functions:
-
- void f();
- void g();
- void main()
- {
- void (**p)(), (**q)();
- // declare p and q as pointers to pointers to void
- functions
- p = new (void (*[3])());
- // p now points to an array of pointers to functions
- q = new void(*[3])(); // error
- // error - bound as 'q = (new void) (*[3])();'
- p[0] = f; // p[0] to point to function
- f
- q[2] = g; // q[2] to point to
- function g
- p[0](); // call f()
- q[2](); // call g()
- }
-
- However, the second use of new causes an erroneous binding of q = (new void)
- (*[3])().
-
- The type-specifier-list cannot contain class declarations, enumeration
- declarations, or const or volatile types. The type-specifier-list can contain a
- pointer to a const or volatile object. For example, const char* is allowed, but
- char* const is not.
-
- Additional arguments can be supplied to new by using the placement syntax. If
- placement arguments are used, a declaration of operator new() with these
- arguments must exist. For example:
-
- #include <stddef.h>
- class X
- {
- public:
- void* operator new(size_t,int, int){ /* ... */ }
- };
- .
- .
- .
- void main ()
- {
- X* ptr = new(1,2) X;
- }
-
- Member Function and the Global operator new()
-
- When an object of a class type is created with the new operator, the member
- operator new() function is implicitly called with the size of the argument as
- its first argument. If you have not defined an operator new() function for the
- class, the global ::operator new() function defined in <new.h> is used. You can
- also define your own global ::operator new(). You can use theallocation
- expression of the form ::operator new() to ensure that the global new operator
- is called, rather than a class member operator new.
-
- When a nonclass object is created with the new operator, the global ::operator
- new() is used.
-
- The order of evaluation of a call to an operator new() is undefined in the
- evaluation of arguments to constructors. If operator new() returns 0, the
- arguments to a constructor may or may not have been evaluated.
- Initializing Objects Created with the new Operator
-
- You can initialize objects created with the new operator in several ways. For
- nonclass objects, or for class objects without constructors, a new-initializer
- expression can be provided in an allocation-expression by specifying (
- expression ) or (). For example:
-
- double* pi = new double(3.1415926);
- int* score = new int(89);
- float* unknown = new float();
-
- If a class has a constructor, the new-initializer must be provided when any
- object of that class is allocated. The arguments of the new-initializer must
- match the arguments of a class constructor, unless the class has a default
- constructor.
-
- You cannot specify an initializer for an array object created with the new
- operator. You can initialize an array of class objects if the class has a
- default constructor. The constructor is called to initialize each array element
- (class object).
-
- Initialization using the new-initializer is performed only if new successfully
- allocates storage.
-
- For more details on the class member operator new() function, see "new and
- delete" in "Special Overloaded Operators" and "Free Store" For additional
- information on constructing and destructing class objects with new and delete,
- see "Constructors and Destructors"
-
-
- ΓòÉΓòÉΓòÉ 4.9.11. delete and delete [ ] ΓòÉΓòÉΓòÉ
-
- The syntax for an expression containing the delete operator is:
-
- deallocation-expression:
- [ :: ] delete
- cast-expression
- [ :: ] delete
- [] cast-expression
-
- The delete operator destroys the object created with new by deallocating the
- memory associated with the object. The delete operator has a void return type.
- The pointer operand must be a pointer that was returned by new, and cannot be a
- pointer to constant. If an attempt to create an object with new fails, the
- pointer returned by new (which will have a zero value) can still be used with
- delete. Deleting a null pointer has no effect.
-
- delete[], rather than delete, is used to destroy objects created with new that
- are not arrays. The array dimensions are not specified with delete[].
-
- An attempt to access a deleted object is undefined because the deletion of an
- object can change its value.
-
- If a destructor has been defined for a class, delete invokes that destructor.
- Whether a destructor exists or not, delete frees the storage pointed to by
- calling the function operator delete() of the class if one exists.
-
- The global ::operator delete() is used if:
-
- o The class has no operator delete()
-
- o The object is of a nonclass type
-
- o The object is deleted with the : expression.
-
- For more details on the class member operator delete() function, see "new and
- delete" in "Special Overloaded Operators" and "Free Store" For additional
- information see "Constructors and Destructors"
-
-
- ΓòÉΓòÉΓòÉ 4.9.12. throw ΓòÉΓòÉΓòÉ
-
- The syntax for the throw expression is:
-
- throw-expression:
- throw
- [assignment-expression]
-
- A throw expression is used to throw exceptions to exception-handlers. It
- causes control to be passed out of the block enclosing the throw statement to
- the first handler whose exception-declaration matches the throw's expression. A
- throw-expression is a unary-expression of type void.
-
- For more details on the throw expression, see "Exception Handling"
-
-
- ΓòÉΓòÉΓòÉ 4.10. Binary Expressions ΓòÉΓòÉΓòÉ
-
- The operators used in binary expressions are:
-
- o Pointer to member
-
- o Multiplication
-
- o Additive
-
- o Bitwise shift
-
- o Relational
-
- o Equality
-
- o Bitwise logical
-
- o Logical
-
- o Conditional
-
- o Assignment
-
- o Comma.
-
-
- ΓòÉΓòÉΓòÉ 4.10.1. Pointer to Member Operators ΓòÉΓòÉΓòÉ
-
- * (pointer to member).
-
- There are two pointer to member operators: .*and ->* . The syntax is:
-
- pm-expression:
-
- cast-expression
- pm-expression .*cast-expression
- pm-expression ->* cast-expression
-
- The .*operator is used to dereference pointers to class members. The first
- operand must be a class type. If the type of the first operand is class type T,
- or is a class that has been derived from class type T, the second operand must
- be a pointer to a member of a class type T.
-
- The ->* operator is also used to dereference pointers to class members. The
- first operand must be a pointer to a class type. If the type of the first
- operand is a pointer to class type T, or is a pointer to a class derived from
- class type T, the second operand must be a pointer to a member of class type T.
-
- The .* and ->* operators bind the cast-expression to the pm-expression,
- resulting in an object or function of the type specified by the second operand.
-
- If the result of.* or ->* is a function, you can only use the result as the
- operand for the ( ) (function call) operator. If the second operand is an
- lvalue, the result of .* or ->* is an lvalue.
-
- For more details on pointer to member operators, see "Pointers to Members" in
- "Class Members and Friends"
-
-
- ΓòÉΓòÉΓòÉ 4.10.2. Multiplicative Operators ΓòÉΓòÉΓòÉ
-
- There are three multiplicative operators: * (multiplication) , / (division) and
- % (modulo or remainder). The syntax is:
-
- multiplicative-expression:
- pm-expression
- multiplicative-expression *
- pm-expression
- multiplicative-expression /
- pm-expression
- multiplicative-expression %
- pm-expression
-
- The operands for * (multiplication) and / (division) must have arithmetic type.
- The operands for % (modulo) must have integral type. The usual arithmetic
- conversions are applied to the operands, and determine the type of the result.
-
- The result of the *operator is the product of the two operands.
-
- The results of the / and % operators are the quotient and remainder of the
- division of the left operand by the right operand. You can use compiler options
- to detect compile-time division by zero errors (division by constant zero).
-
- For more details on generating warning messages for division by constant zero,
- see the -qinfo compiler option described in the Programming Guide.
-
- For details on the standard conversion rules for multiplicative operators, see
- "Arithmetic Conversions"
-
-
- ΓòÉΓòÉΓòÉ 4.10.3. Additive Operators ΓòÉΓòÉΓòÉ
-
- There are two additive operators: + (addition) and - (subtraction). The syntax
- is:
-
- additive-expression:
- multiplicative-expression
- additive-expression +
- multiplicative-expression
- additive-expression -
- multiplicative-expression
-
- The operands must have arithmetic or pointer type.
-
- The result of the + (addition) operator is the sum of the operands. If both
- operands are of arithmetic type, the standard arithmetic conversions are
- applied.
-
- A pointer to an object in an array can be added to a value having integral
- type. The result is a pointer having the same type as the pointer operand. The
- result refers to another element in the array, offset from the original element
- by the amount specified by the integral value. If the resulting pointer points
- to storage outside the array, other than the first location outside the array,
- the result is undefined. The &xcomp. &xcompos2. does not provide boundary
- checking on the pointers.
-
- The result of the - (subtraction) operator is the difference between the
- operands. If both operands are of arithmetic type the standard arithmetic
- conversions are applied. For further details on conversions, see "Arithmetic
- Conversions"
-
- If two pointer types that refer to elements of the same array are subtracted,
- the result is a signed integral value that represents the number of elements
- separating the two elements. Both pointer operands must point to the same
- array, or the result is undefined
-
- If one operand has a pointer type and the other has an integral type, only the
- first operand can be a pointer. You cannot subtract a pointer from an integral
- value.
-
-
- ΓòÉΓòÉΓòÉ 4.10.4. Bitwise Shift Operators ΓòÉΓòÉΓòÉ
-
- There are two bitwise shift operators: << (shift left) and (shift right). The
- syntax is:
-
- shift-expression:
- additive-expression
- shift-expression << additive-expression
- shift-expression >> additive-expression
-
- The operands must have integral type. Integral promotions are performed The
- result has the same type as the left operand. If the right operand is negative,
- or greater than or equal to the length (in bits) of the promoted left operand,
- the result is undefined.
-
- The value of the shift expression exp1 << exp2 is exp1 shifted left by exp2
- bits. The value of exp1 is interpreted as a bit pattern, and vacated bits are
- zero-filled. The value of exp1 >> exp2 is exp1 shifted right by exp2 bits. The
- right shift is guaranteed to be zero-filled if exp1 has an unsigned type or if
- exp1 has a non-negative value. Otherwise, the result is implementation
- dependent. For more details, see "Integers" in "Appendix C.
-
-
- ΓòÉΓòÉΓòÉ 4.10.5. Relational Operators ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 5. Chapter 5. Declarations ΓòÉΓòÉΓòÉ
-
- This chapter discusses the following topics:
-
- o Introduction to Declarations
- o Program linkage
- o Introduction to Specifiers
- o Storage-Class Specifiers
- o Type Specifiers
- o Function Specifiers
- o The typedef Specifier
- o Declarators
- o Type Names
- o Arrays
- o Pointers
- o References
- o Initialization.
-
-
- ΓòÉΓòÉΓòÉ 5.1. Introduction to Declarations ΓòÉΓòÉΓòÉ
-
- A declaration introduces one or more identifiers into a program. There are
- three types of declarations:
-
- o Data object declarations
- o Type declarations
- o Function declarations.
-
- When you declare a data object and the declaration includes a definition,
- storage is allocated for that object. If a declared object is unused or is only
- used as the operand of sizeof, you do not need to define it. When you declare
- or define a type, storage is not allocated.
-
- A declaration establishes the names and type characteristics of data objects,
- functions, and types used in a program. The declaration of data objects,
- functions, and types can occur in local or block scope, file scope, or class
- scope. A declaration can specify a storage class, type, and linkage for an
- object or function. A definition is a declaration that allocates storage for a
- variable or specifies the code or body for a function. Each variable used in
- the program must be defined only once. In the statement where you define a
- variable you can also initialize it.
-
-
- ΓòÉΓòÉΓòÉ 5.1.1. Declaration Grammar ΓòÉΓòÉΓòÉ
-
- A declaration has the following syntax:
-
- declaration:
- [decl-specifiers][declarator-list]
- ;
- function-definition
- template-declaration
- exception-declaration
- linkage-specification
-
- Declaration syntax is recursive and allows for complete declarations.
-
- The details of specific kinds of declarations are described in the following
- sections:
-
- o decl-specifiers are specifiers that can be used in a declaration. .
-
- o function-definition is described in "Function Definitions" Function
- Definitions.
-
- o template-declaration is described in Templates.
-
- o exception-declaration is described in Exception Handling.
-
- o linkage-specification is described in "Linkage Specifications" Linkage
- Specifications - Linking to non-C++ Programs.
-
-
- ΓòÉΓòÉΓòÉ 5.2. Program Linkage ΓòÉΓòÉΓòÉ
-
- The association, or lack of association, between two identical identifiers is
- known as linkage. Linkage is described here because the kind of linkage that an
- identifier has depends on the way that it is declared.
-
- A file scope identifier has one of the following kinds of linkage:
-
- Internal Identical identifiers within a single source file refer to the same
- data object.
-
- External Identical identifiers in separately compiled files refer to the same
- data object.
-
- No linkage Each identical identifier refers to a unique object.
-
- You can use a linkage specification to link to non-C++ declarations. Linkage
- Specifications - Linking to non-C++ Programs for further details.
-
-
- ΓòÉΓòÉΓòÉ 5.2.1. Internal Linkage ΓòÉΓòÉΓòÉ
-
- The following kinds of identifiers have internal linkage:
-
- o Identifiers with file or block scope that have the keyword static in their
- declarations. Functions with static storage class are visible only in the
- source file in which you define them.
-
- o Inline functions
-
- o Identifiers declared at file scope with the specifier const and not
- explicitly declared extern.
-
- A variable that has static storage class can be defined within a block or
- outside of a function. If the definition occurs within a block, the variable
- has internal linkage and is only visible within the block after its declaration
- is seen. If the definition occurs outside of a function, the variable has
- internal linkage and is available from the point where it is defined to the end
- of the current source file.
-
- A class name that has no static members or noninline member functions, and that
- has not been used in the declaration of an object or function is local to its
- translation unit.
-
- If the declaration of an identifier has the keyword extern and if a previous
- declaration of the identifier is visible at file scope, the identifier has the
- same linkage as the first declaration.
-
-
- ΓòÉΓòÉΓòÉ 5.2.2. External Linkage ΓòÉΓòÉΓòÉ
-
- The following kinds of identifiers have external linkage:
-
- o Identifiers with file or block scope that have the keyword extern in their
- declarations. If a previous declaration of the identifier is visible at file
- scope, the identifier has the same linkage as the first declaration. For
- example, a variable or function that is first declared with the keyword
- static and later declared with the keyword extern has internal linkage.
-
- o Function identifiers declared without storage-class specifiers.
-
- o Object identifiers that have file scope declared without a storage-class
- specified. Storage is allocated for such object identifiers.
-
- o Static class members and noninline member functions.
-
- Identifiers declared with the keyword extern can be defined in other
- translation units.
-
-
- ΓòÉΓòÉΓòÉ 5.2.3. No Linkage ΓòÉΓòÉΓòÉ
-
- The following kinds of identifiers have no linkage:
-
- o Identifiers that do not represent an object or a function, including labels,
- enumerators, typedef names, type names, and template names.
-
- o Identifiers that represents a function argument.
-
- o Identifier declared inside a block without the keyword extern.
-
-
- ΓòÉΓòÉΓòÉ 5.2.4. Name Demangling ΓòÉΓòÉΓòÉ
-
- When the &xcomp. &xcompos2. compiles a program, it encodes all function names
- and certain other identifiers to include type and scope information. This
- encoding process is called mangling, and the mangled names are used in the
- object files and final executable file.
-
- You may find it difficult to read the mangled names, so two utilities are
- provided to demangle the encoded names back to their original names.
-
-
- ΓòÉΓòÉΓòÉ 5.3. :id='pJK21d0antl'.Introduction to Specifiers ΓòÉΓòÉΓòÉ
-
- The following sections describe the specifiers that can be used in a
- declaration. Specifiers are used to indicate the storage class, data type, and
- other properties of the object or function you are declaring. The syntax is:
-
- decl-specifier:
- storage-class-specifier
- type-specifier
- fct-specifier
- template-specifier
- friend
- typedef
-
- decl-specifiers:
- [decl-specifiers]
- decl-specifier
-
- The details of specific kinds of specifiers are described in the following
- sections:
-
- o storage-class-specifier is described in
-
- o type-specifier is described in Type Specifiers.
-
- o fct-specifier is described in Function Specifiers.
-
- o The template-specifier is described in Templates.
-
- o The friend specifier is described in Friends
-
- o The typedef specifier is described in "The typedef Specifier" The typedef.
-
-
- ΓòÉΓòÉΓòÉ 5.4. Storage-Class Specifiers ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- storage-class-specifier:
-
- auto
-
- register
-
- extern
-
- static
-
- Declarations with the auto or register storage-class specifier result in
- automatic storage. Those with the extern or static storage-class specifier
- result in static storage.
-
- Most local declarations that do not include the extern storage-class specifier
- allocate storage; however, function declarations and type declarations do not
- allocate storage.
-
- The only storage-class specifiers you can place in a global or file scope
- declaration are static and extern.
-
-
- ΓòÉΓòÉΓòÉ 5.4.1. auto and register ΓòÉΓòÉΓòÉ
-
- auto enables you to define variables with automatic storage whose use is
- restricted to the current block or to blocks enclosed in the current block.
- The storage-class keyword auto is optional in block scope definitions and
- argument declarations. A variable having the auto storage class cannot be
- redeclared. Its first declaration is seen as its definition.
-
- register enables you to indicate within a block scope definition or an argument
- declaration that the variable is heavily used (such as a loop control
- variable). If possible, the compiler places the variable into a machine
- register for faster access. A variable having the register storage class must
- be defined within a block or declared as an argument to a function.
-
- If the compiler does not allocate a machine register for a register variable,
- that variable is treated as having storage class auto. Because of the limited
- size and number of registers available on the system, few variables can be
- stored in registers at the same time.
-
- You can initialize any auto variable or any register variable except arguments.
- If you do not provide an initial value, it is undefined. If you provide an
- initial value, the initializer representing the initial value can be an
- expression. The variable is then set to that initial value each time the
- program block that contains the variable definition is entered.
-
- Unlike C, C++ allows you to take the address of an object with storage class
- register. For example:
-
- register i;
- int* b = &i; // valid in C++, not in C
-
-
- ΓòÉΓòÉΓòÉ 5.4.2. extern ΓòÉΓòÉΓòÉ
-
- Using extern declarations enables you to reference variables and functions
- defined in other files. An extern declaration does not replace the definition.
- It describes the variable or function that is externally defined.
-
- An extern declaration can appear outside a function or at any point in a block.
- In a block, an extern declaration must contain the keyword extern. If the
- declaration describes a function or appears outside a function and describes a
- variable, the keyword extern is optional.
-
- All identifiers with an external definition have static storage.
-
- An extern declaration cannot appear in class scope.
-
- You can initialize any extern variable. If an extern declaration contains an
- initializer, it is a definition. extern objects are initialized before the
- first use of any function or object defined in that file. extern objects that
- are not explicitly initialized will be initialized to 0 (zero) at load time.
- Objects initialized with constant values are initialized first, before dynamic
- initialization takes place. Beyond this, the order of initialization of objects
- from different files is undefined.
-
- You cannot initialize a variable in a block scope declaration that has the
- extern storage-class specifier.
-
-
- ΓòÉΓòÉΓòÉ 5.4.3. static ΓòÉΓòÉΓòÉ
-
- static enables you to define variables or functions that retain storage
- throughout the program. A variable or function defined with static is only
- visible within the file in which it is defined. The keyword static must appear
- in all static variable definitions and static function definitions. A variable
- or function that is declared with extern after it has been declared with static
- has static storage.
-
- All identifiers with a static storage class have static storage.
-
- You can initialize any staticvariable with an expression.
-
- Nonlocal staticobjects in a file are initialized before the first use of any
- function or object defined in that file. These objects are initialized before
- the first statement of main() or at any point before a function or object
- defined in that file is first used. Staticobjects that are not explicitly
- initialized will be initialized to 0 (zero) at load time. Objects initialized
- with constant values are initialized first, before dynamic initialization takes
- place. Beyond this, the order of initialization of objects from different files
- is undefined.
-
- Static variables that are local to a block are initialized only when control
- passes through their definitions for the first time. They retain their value
- from one execution of a block statement to the next. If the local static
- variable is a class object with constructors and destructors, the object will
- be constructed when control passes through its definition for the first time.
- If a local class object is created by a constructor, its destructor is called
- immediately before or as part of the calls of the atexit() functions.
-
-
- ΓòÉΓòÉΓòÉ 5.5. Type Specifiers ΓòÉΓòÉΓòÉ
-
- Type specifiers are used to indicate the type of the object or function being
- declared. Their syntax is:
-
- type-specifier:
- simple-type-name
- class-specifier
- enum-specifier
- elaborated-type-specifier
- const
- volatile
-
- class-specifiers are described in "C++ Classes" -- Reference bfx1270antl not
- found --
-
- class-specifiers are described in "C++ Classes"
-
- The syntax for a simple-type-name is:
-
- simple-type-name:
- complete-class-name
- qualified-type-name
- char
- short
- int
- long
- signed
- unsigned
- float
- double
- void
-
- For more details, on complete-class-name , and on qualified-type-name
-
- The syntax for an elaborated-type-specifier is:
-
- elaborated-type-specifier:
- class-key complete-class-name
- class-key identifier
- enum qualified-class-name
- :: enum-name
- enum enum-name
-
- class-key:
- class
- struct
- union
-
- enum-specifier:
- enum[identifier]
- { [enum-list]
- }
-
- enum-list:
- enumerator
- enum-list , enumerator
-
- enumerator:
- identifier
- identifier = constant-expression
-
- If you specify a storage class, you can omit the type specifier. When you omit
- the type specifier, all variables declared receive the type int.
-
- Type specifiers are described in detail in the following sections:
-
- o "Fundamental Types"
- o "Derived Types"
- o "volatile and const Attributes"
-
-
- ΓòÉΓòÉΓòÉ 5.5.1. Fundamental Types ΓòÉΓòÉΓòÉ
-
- The fundamental data types are:
-
- o Characters
- o Integers
- o Floating-point numbers
- o Void
- o Enumerations.
-
- The integral types are char and int of all sizes. Floating-point numbers can
- have types float, double, or long double. In C++, enumerations are not an
- integral type. Integral and floating point types are collectively called
- arithmetic types.
-
- You can give names to both fundamental and derived types by using the typedef
- construct.
-
-
- ΓòÉΓòÉΓòÉ 5.5.2. Characters ΓòÉΓòÉΓòÉ
-
- The three character data types are char, signed char, and unsigned char. They
- provide enough storage to hold any member of the ASCII character set.
-
- The amount of storage allocated for a char is implementation dependent. For
- further details, see "Characters" in "Appendix C.
-
- For the purposes of distinguishing overloaded functions, char is a distinct
- type from signed char and unsigned char. The default type of char is unsigned
- char.To change this default, use #pragma chars or #pragma options
- respectively. The -qchars option of the compiler also lets you change the
- default sign specification for a char object.
-
- To define or declare a data object having a character data type, place the
- keyword char in the type specifier position of the definition or declaration.
-
- The declarator for a simple character definition or declaration is an
- identifier. You can initialize a simple character with a character constant or
- with an expression that evaluates to an integer.
-
- The following example defines the const char variable end_of_string with the
- initial value '\0' (the null character):
-
- const char end_of_string = '\0';
-
- For further details, see "Character Constants"
-
- The following example defines the unsigned char variable switches with the
- initial value 3. Note that the value of switches is the decimal representation
- of 3 and not the character `3'.
-
- unsigned char switches = 3;
-
- You can use the char specifier in variable definitions to define such complex
- variables as arrays of characters, pointers to characters, and arrays of
- pointers to characters.
-
- The following example defines string_pointer as a pointer to a character:
-
- char *string_pointer;
-
- The following example defines name as a pointer to a character. Initially, name
- points to the first letter in the character string "Johnny".
-
- char *name = "Johnny";
-
- For further details, see "Pointers"
-
- The following example defines a one-dimensional array of pointers to
- characters. The array has three elements. Initially, they are a pointer to the
- string "Venus", a pointer to the string "Jupiter", and a pointer to "Saturn":
-
- static char *planets[ ] = { "Venus", "Jupiter",
- "Saturn"
- };
-
- For further details, see "Arrays"
-
-
- ΓòÉΓòÉΓòÉ 5.5.3. Integers ΓòÉΓòÉΓòÉ
-
- C++ has the following six groups of integer variables:
-
- o short int or short or signed short int or signed short
-
- o signed int or int
-
- o long int or long or signed long int or signed long
-
- o unsigned short int or unsigned short
-
- o unsigned or unsigned int
-
- o unsigned long int or unsigned long.
-
- Note: When the arguments in overloaded functions and overloaded operators are
- integer types, two integer types that both come from the same group are not
- treated as distinct types. For example, you cannot overload an int argument
- against a signed int argument. Overloading and argument matching is described
- in "C++ Overloading"
-
- The default integer type for a bit field is unsigned.
-
- The amount of storage allocated for an int, a short, or a long is
- implementation dependent. For further details, see "Integers" in "Appendix C.
-
- The unsigned prefix causes a variable to be treated as a nonnegative integer.
- Each unsigned type provides the same size storage as its signed equivalent. For
- example, int reserves the same storage as unsigned int. Because a signed type
- reserves a sign bit, an unsigned type can hold a larger positive integer than
- the equivalent signed type.
-
- To define or declare a data object having an integer data type, use
- combinations of one or more of the keywords long, short, signed, unsigned, and
- int, as shown above, in the type specifier position of the definition or
- declaration.
-
- The declarator for a simple integer definition or declaration is an identifier.
- You can initialize a simple integer definition with an integer constant or with
- an expression that evaluates to a value that can be assigned to an integer.
-
- The following example defines the unsigned long int variable ss_number as
- having the initial value 438888834:
-
- unsigned long ss_number = 438888834ul;
-
- The following example defines the int variable sum. The initial value of sum is
- the result of the expression a + b.
-
- int a = 1;
- int b = 2;
- int sum = a + b;
-
- The example would be valid in either block or file scope.
-
-
- ΓòÉΓòÉΓòÉ 5.5.4. Floating Point ΓòÉΓòÉΓòÉ
-
- Numbers
-
- There are three types of floating-point numbers: float, double, and long
- double.
-
- The amount of storage allocated for a float, a double, or a long double is
- implementation dependent. For more details, see "Floating-Point Types" in
- "Appendix C. &ugos2. .
-
- To define or declare a data object having a float data type, use the keywords
- float, double, or long double in the type specifier position of the definition
- or declaration.
-
- The declarator for a simple floating-point definition or declaration is an
- identifier. You can initialize a simple floating-point variable with a float
- constant or with a variable or expression that evaluates to an integer or
- floating-point number.
-
-
- ΓòÉΓòÉΓòÉ 5.5.5. void ΓòÉΓòÉΓòÉ
-
- C++ provides a data type that always represents an empty set of values. The
- keyword for this type is void.The only object you can declare with the type
- specifier void is a pointer. You cannot declare a variable of type void.
-
- When a function does not return a value, use void as the type specifier in the
- function definition and declaration. An argument list for a function taking no
- arguments is void.
-
- You can explicitly convert any expression to type void, but the resulting
- expression can only be used as one of the following:
-
- o An expression statement
- o The left operand of a comma expression
- o The second or third operand in a conditional expression.
-
-
- ΓòÉΓòÉΓòÉ 5.5.6. Enumerations ΓòÉΓòÉΓòÉ
-
- The syntax for an enumeration name is:
-
- enum-name:
- identifier
-
- Note: Unlike C, an enumeration data type in C++ has a distinct type that is
- not an integral type.
-
- Each enumeration has a set of named constants associated with it. You can
- define an enumeration data type and all variables that have that enumeration
- type in one statement, or you can separate the definition of the enumeration
- data type from all variable definitions.
-
- An enumeration type declaration contains the keyword enum followed by an
- identifier (the enumeration name) and a brace-enclosed list of enumerators in
- which a comma separates each enumerator.
-
- The identifier in an enumerator is called an enumeration constant. You can use
- it in any place where values of the enumeration type can be used. Enumeration
- constants can be promoted to signed or unsigned integral constants when used in
- an expression. The &xcomp. &xcompos2. determines the integer representation of
- an enumerator (and its corresponding enumeration constant) by the following
- rules (an earlier rule has precedence over a later one):
-
- 1. If an = (equal sign) and a constant expression follow the enumeration
- constant, the enumeration constant represents the value of the constant
- expression.
-
- 2. If the enumerator is the leftmost value in the list and is not followed by
- an = and a constant expression, the enumeration constant represents 0.
-
- 3. If the enumeration constant is notthe leftmost value in the list and isnot
- followed by an = and a constant expression, the enumeration constant
- represents the integer value that is one greater than the value represented
- by the preceding enumerator.
-
- The following example defines the enumeration data type status.
-
- enum status { run, create, delete=5, suspend };
-
- The data type status represents the following values only: Enumeration
- Constant Integer Representation
-
- run 0
-
- create 1
-
- delete 5
-
- suspend 6
-
- Each enumeration constant must have a unique name within the block or the
- file where the enumeration data type is defined. In the following example,
- the redefinition of average on line 4 and of poor on line 5 cause
- compilation error messages:
-
- 1 func()
- 2 {
- 3 enum score { poor, average, good };
- 4 enum rating { below, average, above };
- 5 int poor;
- 6 }
-
- An enumeration variable definition contains an optional storage-class
- specifier, a type specifier, a declarator, and an optional initializer. The
- type specifier contains the keyword enum, followed by the name of the
- enumeration data type. You must define the enumeration data type before you
- define a variable having that type. The keyword enum is optional in a
- declaration using a predefined enumeration type.
-
- The initializer for an enumeration variable contains the symbol =, followed
- by an enumeration constant of the associated enumeration type. For example:
-
- enum grain { oats, wheat, barley, corn, rice };
- enum grain g_food = barley;
- grain cob_food = corn;
-
- The first line of the previous example defines the enumeration data type
- grain. The second line defines the enumeration constant g_food and gives it
- the initial value of barley. The type specifier enum grain indicates that
- the value of g_food has the enumerated data type grain. The third line
- defines the variable cob_food and gives it the initial value of corn. The
- enum is optional in lines 2 and 3. Line 3 omits it.
-
- You can place a type definition and a variable declaration in one statement
- by placing a declarator and an optional initializer after the type
- definition. To specify a storage class for the variable, you can place the
- storage-class specifier at the beginning of the statement or before the
- declarator. For example, either of the following definitions:
-
- register enum score { poor=1, average, good } rating =
- good;
- enum score { poor = 1, average, good } register rating
- = good;
-
- is equivalent to the following two statements:
-
- enum score { poor=1, average, good };
- register enum score rating = good;
-
- Both examples define the enumeration data type score and the variable
- rating. rating has the storage class register, the data type enum score,
- and the initial value good.
-
- If you combine a data-type definition with the definitions of all variables
- having that data type, you can leave the data type unnamed. The following
- example defines the variable weekday, which can be assigned any of the
- specified enumeration constants:
-
- enum { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday,
- Saturday } weekday;
-
- For more details, see "Constant Expressions" and "Identifiers"
-
-
- ΓòÉΓòÉΓòÉ 5.5.7. Derived Types ΓòÉΓòÉΓòÉ
-
- From the fundamental types, you can derive:
-
- o Arrays
- o Functions
- o Pointers
- o References
- o Constants
- o Structures
- o Unions
- o Classes
- o Pointers to Members
-
-
- ΓòÉΓòÉΓòÉ 5.5.8. volatile and const Attributes ΓòÉΓòÉΓòÉ
-
- The volatile attribute is meant to be used when you are optimizing code. See
- "Qualifiers" in "Appendix C. for details on how volatile affects memory access
- to data objects.
-
- The const attribute explicitly declares a data object as a data item that
- cannot be changed. Its value is set at initialization. Do not use const data
- objects in expressions requiring a modifiable lvalue. For example, a const data
- object cannot appear on the left-hand side of an assignment statement.
-
- For a volatile or const pointer, you must place the keyword between the * and
- the identifier. For example:
-
- int z = 10;
- int * volatile x; // x is a volatile pointer to an
- int
- int * const y; // y is a const pointer to an int
-
- For a pointer to a volatile or const data object, you must place the keyword
- before the *. For example:
-
- volatile int *x; // x is a pointer to a volatile int
- const int *y; // y is a pointer to a const int
-
- The expression: *y = z; is allowed in the first example, but not in the second.
- The expression: y = &z; is allowed in the second example, but not in the first.
-
- For other types of volatile and const variables, the position of the keyword
- within the definition (or declaration) is not important. For example:
-
- volatile struct omega
- {
- int limit;
- char code;
- } group;
-
- provides the same attributes as:
-
- struct omega
- {
- int limit;
- char code;
- } volatile group;
-
- In both examples, only the structure variable group receives the volatile
- attribute. When applied to a class object, the const and volatile attributes
- also apply to the members of that class.
-
- The keywords enum, struct, and union cannot be separated from their tags by the
- keywords volatile or const.
-
- You can declare or define a volatile or const function , provided such a
- function is a member function. You can define or declare any function that
- returns a pointer or reference to a volatile or const object.
-
- If you place a type definition in the same statement as a definition of a
- variable having the volatile or const attribute, the attribute applies to that
- variable only. For example:
-
- enum shape { round, square, triangular, oblong }
- volatile
- object;
- enum shape appearance;
-
- Only the variable object has the volatile attribute. Similarly, if you specify
- the const keyword instead of volatile, only the variable object receives the
- const attribute.
-
- The following code fragments show examples of declarators:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé Example Γöé Description Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé int owner; Γöé owner is an int data object Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé int* node; Γöé node is a pointer to an int Γöé
- Γöé Γöé data object Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé int names[126]; Γöé names is an array of 126 int Γöé
- Γöé Γöé elements Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé int *action( ); Γöé action is a function Γöé
- Γöé Γöé returning a pointer to an int Γöé
- Γöé Γöé and taking no arguments Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé volatile int min; Γöé min is an int that has the Γöé
- Γöé Γöé volatile attribute Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé int* volatile volume; Γöé volume is a volatile pointer Γöé
- Γöé Γöé to an int Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé volatile int* next; Γöé next is a pointer to a vola- Γöé
- Γöé Γöé tile int Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé volatile int* sequence[5]; Γöé sequence is an array of five Γöé
- Γöé Γöé pointers to volatile int Γöé
- Γöé Γöé objects Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé extern const volatile int Γöé op_system_clock is an extern Γöé
- Γöé op_system_clock; Γöé int that has the volatile and Γöé
- Γöé Γöé const attributes Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
-
- ΓòÉΓòÉΓòÉ 5.6. Function Specifiers ΓòÉΓòÉΓòÉ
-
- Function specifiers are used only in function declarations. For further
- details, see "Function Declarations"
-
- The syntax is:
-
- fct-specifier:
- inline
- virtual
-
- The function specifier inline is used to make a suggestion to the compiler to
- incorporate the code of a function into the code at the point of the call. For
- more details, see "Inline Functions"
-
- The function specifier virtual can only be used in nonstatic member function
- declarations. For further details, see "Virtual Functions"
-
-
- ΓòÉΓòÉΓòÉ 5.7. The typedef ΓòÉΓòÉΓòÉ
-
- Specifier
-
- typedef declarations allow you to define your own identifiers that can be used
- in place of type specifiers such as int, float, and double. The data types you
- define using typedef are not new data types. They are synonyms for the types
- that they represent. A typedef definition does not reserve storage.
-
- When you define an object using a typedef identifier, the properties of the
- defined object are exactly the same as if you had defined it by explicitly
- listing the data type associated with the typedef. For example, the following
- statements declare LENGTH as a synonym for int, and then uses this typedef to
- declare length, width, and height as int variables:
-
- typedef int LENGTH;
- LENGTH length, width, height;
-
- The following declarations are equivalent to the above declaration:
-
- int length, width, height;
-
- Similarly, typedef can define class types. For example,
-
- typedef struct
- {
- int kilos;
- int grams;
- } WEIGHT;
-
- The structure WEIGHT can then be used in the following declarations:
-
- WEIGHT chicken, cow, horse, whale;
-
- A class defined in a typedef without being named is given a dummy name and the
- typedef name for linkage. Such a class cannot have constructors or destructors.
- For example,
-
- typedef class
- {
- Trees();
- } Trees;
-
- Here the function Trees() is an ordinary member function of a class whose type
- name is unspecified. In the above example, Trees is an alias for the unnamed
- class, not the class type name itself, so Trees() cannot be a constructor for
- that class.
-
-
- ΓòÉΓòÉΓòÉ 5.8. Declarators ΓòÉΓòÉΓòÉ
-
- A declaration can consist of a specifier followed by a list of declarators. A
- declarator designates the name of a data object or function. In a declarator,
- you can specify the type of an object to be an array, a pointer, or a
- reference. You can specify that the return type of a function is a pointer or a
- reference. You can also perform initialization in a declarator. The following
- sections describe each of these topics:
-
- o "Type Names"
- o "Arrays"
- o "Pointers"
- o "References"
- o "Initializers"
-
- The syntax for a declarator list is :
-
- declarator-list:
- init-declarator
- declarator-list , init-declarator
- init-declarator:
- declarator [initializer]
-
- The syntax for a declarator is:
-
- declarator:
- dname
- ptr-operator declarator
- declarator
- (argument-declaration-list)
- [cv-qualifier-list]
- [exception-specification]
- declarator [
- [constant-expression]
- ]
- (declarator)
- ptr-operator:
- *[cv-qualifier-list]
- &[cv-qualifier-list]
- complete-class-name :: *
- [cv-qualifier-list]
- cv-qualifier-list:
- cv-qualifier
- [cv-qualifier-list]
- cv-qualifier:
- const
- volatile
- dname:
- name
- class-name
- ~ class-name
- typedef-name
- qualified-type-name
-
- The grammar for qualified-type-name above applies to types at file scope.
-
-
- ΓòÉΓòÉΓòÉ 5.9. Type Names ΓòÉΓòÉΓòÉ
-
- Type names are used to explicitly specify type conversions and as an argument
- to the operators sizeof and new . A type name looks like a declaration for an
- object or function except that the actual name of the object or function does
- not appear.
-
- The syntax is:
-
- type-name
- type-specifier-list
- [abstract-declarator]
- type-specifier-list
- type-specifier
- [type-specifier-list]
- abstract-declarator
- ptr-operator
- [abstract-declarator]
- [abstract-declarator]
- (argument-declaration-list)
- [cv-qualifier-list]
- [abstract-declarator]
- [[constant-expression]]
- (abstract-declarator)
-
- argument-declaration-list:
- [arg-declaration-list]
- [...]
- [arg-declaration-list] , ...
-
- arg-declaration-list:
- argument-declaration
- arg-declaration-list ,
- argument-declaration
- argument-declaration:
- decl-specifiers declarator
- decl-specifiers declarator =
- expression
- decl-specifiers
- [abstract-declarator]
- decl-specifiers
- [abstract-declarator]
- = expression
-
- In the following example, N and arraytype are both type names.
-
- class N {int i};
- typedef int arraytype [5];
-
-
- ΓòÉΓòÉΓòÉ 5.10. Arrays ΓòÉΓòÉΓòÉ
-
- An array contains an ordered group of adjacent data objects. Each of these
- objects is called an element. All elements within an array have the same data
- type.
-
- Arrays can be of any data type, except function or reference. You can, however,
- declare an array of pointers to functions.
-
- A subscript declarator has the form:
-
- declarator [
- [constant-expression]
- ]
-
- The declarator contains an identifier followed by a subscript declarator. The
- identifier can be preceded by an * (asterisk), making the variable an array of
- pointers. The subscript declarator describes the number of dimensions in the
- array and the number of elements in each dimension.
-
- Each bracketed expression describes a different dimension. If the brackets
- contain a constant expression, the constant expression must have a positive
- integral value. The value of the constant expression determines the number of
- elements in that dimension. The following example defines a one-dimensional
- array that contains four elements having type char:
-
- char list[4];
-
- The first subscript of each dimension is 0 (zero). Thus, the array list
- contains the elements:
-
- list[0]
- list[1]
- list[2]
- list[3]
-
- The following example defines the two-dimensional array roster containing six
- elements of type int.
-
- int roster[3][2];
-
- In multidimensional arrays, when elements are referenced in order of increasing
- storage location, the last subscript varies the fastest. Thus, the array roster
- contains the elements:
-
- roster[0][0]
- roster[0][1]
- roster[1][0]
- roster[1][1]
- roster[2][0]
- roster[2][1]
-
- You can leave the first (and only the first) set of subscript brackets empty
- in:
-
- o Array definitions that contain initializations
- o extern declarations
- o Argument declarations.
-
- In array definitions that leave the first set of subscript brackets empty, the
- initializer determines the number of elements in the first dimension. In a
- one-dimensional array, the number of initialized elements becomes the total
- number of elements. In a multidimensional array, the initializer is compared to
- the subscript declarator to determine the number of elements in the first
- dimension. In a multidimensional array, every dimension except the first must
- be specified as a constant expression.
-
- An unsubscripted array name (for example, region instead of region[4])
- represents a pointer whose value is the address of the first element of the
- array, provided the array has previously been declared. An unsubscripted array
- name with square brackets (for example, region[]) is allowed only when
- declaring arrays at file scope or in the argument list of a function
- declaration. In declarations, only the first dimension can be left empty; you
- must specify the sizes of additional dimensions.
-
- The following example shows an argument declaration for a one-dimensional
- array:
-
- test(int y[ ])
- { /* ... */ }
-
- The array subscript operator is described in "Array Subscript"
-
- See also "Array Initialization"
-
-
- ΓòÉΓòÉΓòÉ 5.11. Pointers ΓòÉΓòÉΓòÉ
-
- This section discusses the following topics:
-
- o Pointer types
- o Pointer assignment
- o Using pointers
- o Pointer arithmetic
- o Pointer type compatibility.
-
- Using pointers to functions is described in "Pointers to Functions".
-
-
- ΓòÉΓòÉΓòÉ 5.11.1. Pointer Types ΓòÉΓòÉΓòÉ
-
- A pointer type variable holds the address of a data object or a function. A
- pointer can refer to an object of any one data type except to a bit field, or
- to a reference. Some common uses for pointers are:
-
- o To pass the address of a variable to a function (you can also use a reference
- to do this). By referencing the address of a variable, a function can change
- the contents of that variable. See "Calling Functions and Argument Passing".
-
- o To access dynamic data structures such as linked lists, trees, and queues.
-
- o To access elements of an array or members of a class.
-
- o To access an array of characters as a string.
-
- A pointer can have any storage class. The following example declares pcoat as a
- pointer to an object having type long:
-
- extern long *pcoat;
-
- If the keyword volatile appears before the *, the declarator describes a
- pointer to a volatile object. If the keyword volatile comes between the * and
- the identifier, the declarator describes a volatile pointer.
-
- The keyword const operates the same way as the volatile keyword. In the
- following example, pvolt is a constant pointer to an object having type short:
-
- short * const pvolt;
-
- The following example declares pnut as a pointer to an int object having the
- volatile attribute:
-
- extern int volatile *pnut;
-
- The following example defines (and declares) psoup as a volatile pointer to an
- object having type float:
-
- float * volatile psoup;
-
- The following example defines (and declares) phen as a pointer to an
- enumeration object of type bird:
-
- enum bird *phen;
-
- The next example declares pvish as a pointer to a function that takes no
- arguments and that returns a char value:
-
- char (*pvish)();
-
-
- ΓòÉΓòÉΓòÉ 5.11.2. Pointer Assignment ΓòÉΓòÉΓòÉ
-
- When you use a pointer in an assignment operation, you must ensure that the
- types on both sides of the assignment operator are compatible. For example:
-
- int a=3;
- float b=4.0;
- int* ptra;
- float* ptrb;
-
- void main()
- {
- ptra=&a; // int* ptra points to int a
- ptrb=&b; // float* ptrb points to float b
- ptra=&b; // error, an int* can't point to a float
- ptrb=&a; // error, a float* can't point to an
- int
- ptra=ptrb; // error, can't convert from float*
- to int*
- }
-
- The first two assignment operations are correct. The third and fourth are
- errors because you cannot assign the address of a variable of one type to a
- pointer of a different type. The final assignment fails because the address
- contained in a pointer to float cannot be assigned to a pointer to int.
-
-
- ΓòÉΓòÉΓòÉ 5.11.3. Using Pointers ΓòÉΓòÉΓòÉ
-
- Two operators are commonly used in working with pointers. The * (indirection)
- operator accesses the object pointed to by a pointer. The & (address) operator
- obtains a pointer to its operand.
-
- For example, the following statement assigns the address of x to the variable
- p_to_x. The variable p_to_x has been defined as a pointer.
-
- int x, *p_to_x;
- p_to_x = &x;
-
- The following statement assigns to y the value of the object to which p_to_x
- points:
-
- float y,*p_to_x;
- // ...
- y = *p_to_x;
-
- The following statement assigns the value of y to the variable that *p_to_x
- references:
-
- char y,*p_to_x;
- // ...
- *p_to_x = y;
-
- You cannot use pointers to address bit fields or objects of reference type.
-
-
- ΓòÉΓòÉΓòÉ 5.11.4. Pointer Arithmetic ΓòÉΓòÉΓòÉ
-
- You can perform a limited number of arithmetic operations on pointers. They
- are:
-
- o Increment and decrement
- o Addition and subtraction
- o Comparison
- o Assignment.
-
- The ++ (increment) operator increases the value of a pointer by the size of the
- data object to which the pointer refers. If the pointer refers to the second
- element in an array, the ++ operator makes the pointer refer to the third
- element in the array.
-
- The - - (decrement) operator decreases the value of a pointer by the size of
- the data object to which the pointer refers. If the pointer refers to the
- second element in an array, the - - operator makes the pointer refer to the
- first element in the array.
-
- If the pointer p points to the first element in an array, the following
- expression causes the pointer to point to the third element in the same array:
-
- p = p + 2;
-
- If you have two pointers that point to the same array, you can subtract one
- pointer from the other. This operation yields the number of elements in the
- array that separate the two addresses to which the pointers refer.
-
- You can compare two pointers with the following operators: ==, !=, <, >, <=,
- and >=.
-
- Pointer comparisons using relational operators are defined only when the
- pointers point to elements of the same array. Pointer comparisons using the ==
- and != operators can be performed even when the pointers point to elements of
- different arrays.
-
- You can assign to a pointer the address of a data object, the value of another
- pointer of compatible type, or any constant expression that evaluates to 0
- (zero).
-
-
- ΓòÉΓòÉΓòÉ 5.11.5. Pointer Type Compatibility ΓòÉΓòÉΓòÉ
-
- A pointer to a type has the type type*. Once a pointer has been declared for a
- given type, it cannot be assigned the address of a variable of a different type
- except with an explicit type cast.
-
- Both an assignment of the address of a variable of one type to a pointer of
- another type, and an assignment of a pointer of one type to a pointer of
- another type, are flagged as compile time errors.
-
- For further details on pointer operators, see "Address"
-
- See also "Pointer Initialization"
-
-
- ΓòÉΓòÉΓòÉ 5.12. References ΓòÉΓòÉΓòÉ
-
- A reference is an alias or an alternative name for an object. All operations
- applied to a reference act on the object to which the reference refers. The
- address of a reference is the address of the aliased object.
-
- A reference type is defined by placing the & after the type specifier. You must
- initialize a reference when it is defined.
-
- Because arguments are passed by value, a function call does not modify the
- actual values of the arguments. If a function needs to modify the actual value
- of an argument, the argument must be passed "by reference" (as opposed to being
- passed by value). This can be done using either references or pointers. In C++
- this is accomplished transparently. Unlike C, C++ does not force you to use
- pointers if you want to pass arguments "by reference". For example:
-
- int f(int&);
- void main()
- {
- extern int i;
- f(i);
- }
-
- You cannot tell from the function call f(i) that the argument is being passed
- by reference.
-
- NULL references are not allowed.
-
- For more details on passing by reference, see "Passing Arguments by Reference"
- See "Reference Initialization" for more details on the initialization of
- references.
-
-
- ΓòÉΓòÉΓòÉ 5.13. Initialization ΓòÉΓòÉΓòÉ
-
- This section discusses initializers and initialization of the following:
-
- o Scalar objects
- o Arrays
- o Pointers
- o References
- o Aggregate objects.
-
- Initialization of class objects using constructors is described in
- "Initialization by Constructor".
-
-
- ΓòÉΓòÉΓòÉ 5.13.1. Initializers ΓòÉΓòÉΓòÉ
-
- An initializer is an optional part of a data definition that specifies an
- initial value of a data object.
-
- An initializer has the form:
-
- initializer:
- = expression
- = { [ initializer-list
- ,
- ] }
- (expression-list)
- initializer-list:
- expression
- initializer-list , expression
- [ initializer-list , ]
-
- An initializer of the form (expression-list ) can be used to initialize
- classes. For more details on initializing classes, see "Initialization by
- Constructor" You can also use this form to initialize fundamental types. For
- example, the following two initializations are identical:
-
- int x = 1;
-
- int x(1);
-
- The initializer may consist of the = symbol followed by an initial expression,
- which evaluates to the initial value of the data object. Unlike, ANSI C, you
- can initialize variables at file scope with nonconstant expressions.
-
- An attempt to jump past declarations that contain initializations will produce
- a compilation error. For example, the following is not valid in C++ :
-
- goto skiplabel;
- int i=3 // error, jumped over declaration of i
- // with initializer
- skiplabel: i=4;
-
-
- ΓòÉΓòÉΓòÉ 5.13.2. Scalar Initialization ΓòÉΓòÉΓòÉ
-
- To assign a value to a scalar data object, you can either:
-
- o Use the simple initializer = expression.
-
- o Use parentheses.
-
- For example, the following two data definitions set the initial values of both
- group and combo to 3:
-
- int group = 3;
- int combo(3);
-
-
- ΓòÉΓòÉΓòÉ 5.13.3. Array Initialization ΓòÉΓòÉΓòÉ
-
- You can initialize array definitions. The initializer contains the = symbol
- followed by a brace-enclosed comma-separated list of expressions. You do not
- need to initialize all elements in an array. In extern and static array
- definitions, all elements are initialized with the value 0 (zero). In partially
- initialized arrays, elements that are not initialized receive the value 0
- (zero).
-
- The following definition shows a completely initialized one-dimensional array:
-
- static int number[3] = { 5, 7, 2 };
-
- The array number contains the following values: Element Value
-
- number[0] 5
-
- number[1] 7
-
- number[2] 2
-
- The following definition shows a partially initialized one-dimensional array:
-
- static int number1[3] = { 5, 7 };
-
- The values of number1 are: Element Value
-
- number1[0] 5
-
- number1[1] 7
-
- number1[2] 0
-
- Instead of defining the number of elements with an expression in the subscript
- declarator, the following one-dimensional array definition defines one element
- for each initializer specified:
-
- static int item[ ] = { 1, 2, 3, 4, 5 };
-
- The &xcomp. &xcompos2. gives item the five initialized elements: Element
- Value
-
- item[0] 1
-
- item[1] 2
-
- item[2] 3
-
- item[3] 4
-
- item[4] 5
-
- You can initialize a one-dimensional character array by specifying either of:
-
- o A brace-enclosed comma-separated list of character constants
-
- o A string literal. Braces surrounding the string literal are optional.
-
- Initializing an array with a string literal places the character '\0' at the
- end of the string. You cannot have more initializers than there are array
- elements.
-
- The following character array initialization produces an error:
-
- static char name3[3] = "Jan"; // error
-
- You must have an element available to contain the '\0' that is appended to the
- string.
-
- static char name4[4] = "Jan"; // legal
-
-
- ΓòÉΓòÉΓòÉ 5.13.4. Pointer Initialization ΓòÉΓòÉΓòÉ
-
- A pointer initializer is an = (equal sign) followed by the address the pointer
- is to contain. The following example defines the variables time and speed as
- having type double and amount as having type pointer to a double. The pointer
- amount is initialized to point to total:
-
- double total, speed, *amount = &total;
-
- An unsubscripted array name is refers to a pointer to the first element in the
- array. To assign the address of the first element of an array to a pointer,
- specify the name of the array. The following two sets of definitions are
- equivalent. Both define the pointer student and initialize student to the
- address of the first element in class:
-
- int class[80];
- int *student = class;
-
- This is equivalent to:
-
- int class[80];
- int *student = &class[0];
-
- You can assign the address of the first character in a string literal to a
- pointer by specifying the string literal in the initializer. The following
- example defines the pointer variable string and the string literal "abcd". The
- pointer string is initialized to point to the character 'a' in the string
- "abcd".
-
- char *string = "abcd";
-
- The following example defines weekdays as an array of pointers to string
- literals. Each element points to a different string. The object weekdays[2],
- for example, points to the string "Tuesday".
-
- static char *weekdays[ ] =
- {
- "Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday"
- };
-
- A pointer can also be initialized to the integer constant 0 (zero). Such a
- pointer is called a null pointer. It does not point to any object.
-
-
- ΓòÉΓòÉΓòÉ 5.13.5. Reference Initialization ΓòÉΓòÉΓòÉ
-
- The object that you use to initialize a reference must be of the same type as
- the reference, or it must be of a type that is convertible to the reference
- type. If you initialize a constant reference using an object that requires
- conversion, a temporary object is created. In the following example, a
- temporary object of type float is created:
-
- int i;
- const float& f = i;
-
- Once a reference has been initialized, it cannot be modified to refer to
- another object. For example:
-
- int num1 = 10;
- int num2 = 20;
- int &RefOne = num1; // valid
- int &RefOne = num2; // error, two definitions
- of RefOne
- RefOne = num2; // assign num2 to num1
- int &RefTwo; // error, uninitialized reference
- int &RefTwo = num2; // valid
-
- Note that the initialization of a reference is not the same as an assignment to
- a reference. Initialization operates on the actual reference by initializing
- the reference with the object it is an alias for. Assignment operates through
- the reference on the object referred to.
-
- A reference can be declared without an initializer:
-
- o When it is used in an argument declaration
-
- o In the declaration of a return type for a function call
-
- o In the declaration of class memberwithin its class declaration
-
- o When the extern specifier is explicitly used.
-
- You cannot have references to references, references to bit fields, arrays of
- references, or pointers to references.
-
-
- ΓòÉΓòÉΓòÉ 5.13.6. Aggregate Initialization ΓòÉΓòÉΓòÉ
-
- An aggregate is an array or an object of a class with no private or protected
- members, no constructors, no base classes, and no virtual functions.
-
- For aggregate classes, the set of initial expressions must be enclosed in { }
- (braces) unless the initializer is a string literal. Individual expressions
- must be separated by commas. Groups of expressions can be enclosed in braces
- and separated by commas.
-
- The number of initializers must be less than or equal to the number of objects
- being initialized. If the set of initial expressions contains fewer
- initializers than the aggregate contains subscripts or members, the trailing
- members are initialized to zero of the appropriate type. The order of
- initializers must match the order of the aggregate's subscripts or members. If
- the aggregate contains subaggregates, the order of subaggregate initialization
- must match the subaggregate member or subscript order.
-
- You can initialize classes in external, static, and automatic definitions. The
- initializer contains an = (equal sign) followed by a brace-enclosed,
- comma-separated list of values. You do not need to initialize all members of a
- class.
-
- The following definition shows a completely initialized structure:
-
- struct address
- {
- int street_no;
- char *street_name;
- char *city;
- char *prov;
- char *postal_code;
- };
- static struct address perm_address =
- { 9876, "Goto St.", "Cville", "Ontario", "X9X
- 1A1"};
-
- The values of perm_address are:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé Member Γöé Value Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé perm_address.street_no Γöé 9876 Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé perm_address.street_name Γöé address of string "Goto St." Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé perm_address.city Γöé address of string "Cville" Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé perm_address.prov Γöé address of string "Ontario" Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé perm_address.postal_code Γöé address of string "X9X 1A1" Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- You can only initialize the first member of a union.
-
- The following example shows how to initialize the first union member birthday
- of the union variable people:
-
- union
- {
- char birthday[9];
- int age;
- float weight;
- } people = {"23/07/57"};
-
-
- ΓòÉΓòÉΓòÉ 5.14. Related Information ΓòÉΓòÉΓòÉ
-
- "Expressions and Operators"
-
- "C++ Classes"
-
-
- ΓòÉΓòÉΓòÉ 6. Chapter 6. Standard Conversions ΓòÉΓòÉΓòÉ
-
- There are two kinds of type conversions: standard conversions and user-defined
- conversions. This chapter describes standard conversions. User-defined
- conversion are discussed in "User-Defined Conversions" Explicit type
- conversions are discussed under "Cast Expressions"
-
- This chapter begins with a discussion of integral promotions. It then describes
- the following implicit standard type conversions :
-
- o Signed integer conversions
- o Unsigned integer conversions
- o Floating-point conversions
- o Pointer conversions
- o Reference conversions
- o Pointer to member conversions.
-
- The chapter concludes with a discussion of arithmetic conversions. Arithmetic
- conversions are used for matching operands of arithmetic operators.
-
- The implementation of type conversions is described in "Type Conversions" in
- "Appendix C.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 6.1. Integral Promotions ΓòÉΓòÉΓòÉ
-
- Certain fundamental types can be used wherever an integer may be used. The
- fundamental types that can be converted through integral promotion are:
-
- o char
- o short int
- o enumerators
- o objects of enumeration type
- o bit-fields (both signed and unsigned).
-
- In integral promotions the value is converted to an int, or an unsigned int if
- the value cannot be represented by an int.
-
-
- ΓòÉΓòÉΓòÉ 6.2. Type Conversions ΓòÉΓòÉΓòÉ
-
- Many C++ language operators cause implicit type conversions, which change the
- type of a value. When you add values having different data types, both values
- are first converted to the same type. For example, when a short int value and
- an int value are added together, the short int value is converted to the int
- type.
-
- For example, implicit type conversions can occur when:
-
- o An operand is prepared for an arithmetic or logical operation.
-
- o An assignment is made to an lvalue that has a different type than the
- assigned value.
-
- o A function is provided a value that has a different type than the parameter.
-
- o The value specified in the return statement of a function has a different
- type than the defined return type for the function.
-
- You can perform explicit type conversions using the cast operator or the
- function style cast. For more details on explicit type conversions, see "Cast
- Expressions"
-
-
- ΓòÉΓòÉΓòÉ 6.2.1. Signed Integer Conversions ΓòÉΓòÉΓòÉ
-
- C++ converts a signed integer to a shorter integer by truncating the high-order
- bits and converting the variable to a longer signed integer by sign-extension.
- Conversion of signed integers to floating-point values takes place without loss
- of information except when an int value is converted to a float, in which case
- some precision may be lost. To convert a signed integer to an unsigned integer,
- the signedinteger is converted to the size of the unsigned integer and the
- result is interpreted as an unsigned value.
-
-
- ΓòÉΓòÉΓòÉ 6.2.2. Unsigned Integer Conversions ΓòÉΓòÉΓòÉ
-
- An unsigned integer is converted to a shorter unsigned or signed integer by
- truncating the high-order bit. An unsigned integer is converted to a longer
- unsigned or signed integer by zero-extending. Zero-extending pads the longer
- integer's leftmost bits with binary zeros.
-
- When an unsigned integer is converted to a signed integer of the same size, no
- change in the bit pattern occurs. However, the value changes if the sign bit is
- set.
-
-
- ΓòÉΓòÉΓòÉ 6.2.3. Floating Point Conversions ΓòÉΓòÉΓòÉ
-
- A float value converted to a double undergoes no change in value. A double
- converted to a float is represented exactly, if possible. If C++ cannot exactly
- represent the double value as a float, the value loses precision. If the value
- is too large to fit into a float, the result is undefined.
-
- When a floating-point value is converted to an integer value, the decimal
- fraction portion of the floating-point value is discarded in the conversion. If
- the result is too large for the given integer type, the result of the
- conversion is undefined.
-
-
- ΓòÉΓòÉΓòÉ 6.2.4. Pointer Conversions ΓòÉΓòÉΓòÉ
-
- Pointer conversions are performed when pointers are used, including pointer
- assignment, initialization, and comparison.
-
- A constant expression that evaluates to zero can be converted to a pointer.
- This pointer will be a null pointer (pointer with a zero value) and is
- guaranteed not to point to any object.
-
- Any pointer to an object that is not a const or volatile object can be
- converted to a void*. You can also convert any pointer to a function to a
- void*, provided that a void* has sufficient bits to hold it.
-
- You can convert an expression with type array of some type to a pointer to the
- initial element of the array except when the expression is used as the operand
- of the & (address) operator or the sizeof operator.
-
- You can convert an expression with a type of function returning T to a pointer
- to a function returning T except when the expression is used as the operand of
- the & (address) operator, the () (function call) operator, or the sizeof
- operator.
-
- You can convert a pointer to a class A to a pointer to an accessible base class
- B of that class, as long as the conversion is not ambiguous. The conversion is
- ambiguous if the expression for the accessible base class can refer to more
- than one distinct class. The resulting value points to the base class subobject
- of the derived class object. A null pointer (pointer with a zero value) is
- converted into itself.
-
- Note: You cannot convert a pointer to a class into a pointer to its base class
- if the base class is a virtual base class of the derived class.
-
- You can convert an integer value to an address offset.
-
- For more details on pointer conversions, see "Pointer Arithmetic"
-
-
- ΓòÉΓòÉΓòÉ 6.2.5. Reference Conversions ΓòÉΓòÉΓòÉ
-
- A reference conversion can be performed wherever a reference initialization
- occurs, including reference initialization done in argument passing and
- function return values. A reference to a class can be converted to a reference
- to an accessible base class of that class as long as the conversion is not
- ambiguous. The result of the conversion is a reference to the base class
- subobject of the derived class object.
-
- Reference conversion is allowed if the corresponding pointer conversion is
- allowed.
-
-
- ΓòÉΓòÉΓòÉ 6.2.6. Pointer to Member Conversions ΓòÉΓòÉΓòÉ
-
- Pointer to member conversion can occur when pointers to members are
- initialized, assigned, or compared.
-
- A constant expression that evaluates to zero is converted to a distinct pointer
- to a member.
-
- A pointer to a member of a base class can be converted to a pointer to a member
- of a derived class if the following conditions are true:
-
- o The conversion is not ambiguous. The conversion is ambiguous if there are
- multiple instances of the base class in the derived class.
-
- o The reverse conversion from a pointer to the derived class to a pointer to
- the base class is accessible.
-
- Note: A pointer to a member is not the same as a pointer to an object or a
- pointer to a function.
-
-
- ΓòÉΓòÉΓòÉ 6.2.7. Other Conversions ΓòÉΓòÉΓòÉ
-
- By definition the void type has no value. Therefore, it cannot be converted to
- any other type, and no other value can be converted to void by assignment.
- However, a value can be explicitly cast to void.
-
- You can convert from an enum to any integral type but not from an integral
- type to an enum.
-
- No conversions between structure or union types are allowed. There are no
- standard conversions between class types.
-
-
- ΓòÉΓòÉΓòÉ 6.3. Arithmetic Conversions ΓòÉΓòÉΓòÉ
-
- Most C++ operators perform type conversions to bring the operands of an
- expression to a common type or to extend short values to the integer size used
- in RISC System/6000 operations. The conversions depend on the specific operator
- and the type of the operand or operands. However, many operators perform
- similar conversions on operands of integer and floating-point types. These
- standard conversions are known as the arithmetic conversions because they apply
- to the types of values ordinarily used in arithmetic.
-
- The implementation of type conversions on arithmetic types is described in
- "Type Conversions" in "Appendix C.
-
- Arithmetic conversion follows this order of precedence:
-
- 1. If one operand has long double type, the other operand is converted to long
- double type.
-
- 2. If one operand has double type, the other operand is converted to double.
-
- 3. If one operand has float type, the other operand is converted to float.
-
- 4. If one operand has unsigned long int type, the other operand is converted
- to unsigned long int.
-
- 5. If one operand has unsigned int type and the other operand has long int
- type and the value of the unsigned int can be represented in a long int,
- the operand with unsigned int type is converted to long int.
-
- 6. If one operand has unsigned int type and the other operand has long int
- type and the value of the unsigned int cannot be represented in a long int,
- both operands are converted to unsigned long int.
-
- 7. If one operand has long int type, the other operand is converted to long
- int.
-
- 8. If one operand has unsigned int type, the other operand is converted to
- unsigned int.
-
- 9. Lastly, both operands are converted to have int type and the result is of
- type int.
-
-
- ΓòÉΓòÉΓòÉ 6.4. Related Information ΓòÉΓòÉΓòÉ
-
- "Expressions and Operators"
-
- "Functions"
-
-
- ΓòÉΓòÉΓòÉ 7. Chapter 7. C++ Statements ΓòÉΓòÉΓòÉ
-
- This chapter describes statement syntax and the following C++ language
- statements:
-
- o Statement grammar
- o Labeled statements
- o Compound statements
- o Expression and declaration statements
- o Selection statements
- o Iteration statements
- o Jump statements
- o Null statement.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 7.1. Statement Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for a statement is:
-
- statement:
- labeled-statement
- expression-statement
- compound-statement
- selection-statement
- iteration-statement
- jump-statement
- declaration-statement
- try-block
-
- The syntax and description for a try-block are described in "Chapter 15.
- Exception Handling" beginning on page -- Reference CPLRexcHardCopy not found
- --.
-
-
- ΓòÉΓòÉΓòÉ 7.2. Labeled Statements ΓòÉΓòÉΓòÉ
-
- A label is an identifier that allows your program to transfer control to other
- statements within the same function. A label is the only identifier that has
- function scope. Labels cannot be redeclared within a function. Control is
- transferred to the statement following the label by means of the goto or
- switch statements. You can use a label in a goto statement before the label
- has been defined.
-
- The syntax is:
-
- labeled-statement:
- identifier : statement
- case constant-expression
- : statement
- default :
- statement
-
- The case and default labels are restricted to use within switch statements.
-
- For further details on function scope, see "Function Scope"
-
-
- ΓòÉΓòÉΓòÉ 7.3. Compound Statements ΓòÉΓòÉΓòÉ
-
- A statement can be either a single statement or a compound statement. A
- compound statementor block lets you group any number of data definitions,
- declarations, and statements into one statement. All definitions, declarations,
- and statements enclosed within a single set of braces are treated as a single
- statement. You can place a compound statement wherever a single statement is
- allowed.
-
- The syntax is:
-
- compound-statement:
- {[statement-list]
- }
- statement-list:
- statement
- statement-list statement
-
- Definitions and declarations can occur anywhere a statement can occur.
-
- If you redefine a data object inside a nested block, the inner object hides the
- outer object while the inner block is processed. Defining several variables in
- different scopes with the same name can make a program difficult to understand
- and maintain. You should avoid redefinitions of identifiers within nested
- blocks.
-
- If a data object is usable within a block and its identifier is not redefined,
- all nested blocks can use that data object.
-
-
- ΓòÉΓòÉΓòÉ 7.3.1. Initialization within Compound Statements ΓòÉΓòÉΓòÉ
-
- Initialization of an auto or register variable occurs each time the statement
- is executed. Initialization of static variables in a block occurs the first
- time the statement containing the initialization is executed. You cannot
- initialize an extern variable within a block.
-
- Note: Unlike ANSI C, in C++ it is an error to jump over a declaration or
- definition containing an initializer.
-
- The following code produces an error in C++ :
-
- goto skiplabel;
- int i=3 // error, jumped over decl. of i with initializer
- skiplabel: i=4;
-
- The following example shows how the values of data objects change in nested
- blocks:
-
- 1 #include <iostream.h>
- 2
- 3 void main()
- 4 {
- 5 int x = 1; // initialize x to 1
- 6 int y = 3;
- 7
- 8 if (y > 0)
- 9 {
- 10 int x = 2; // initialize x to 2
- 11 cout << "second x = " << x <<
- endl;
- 12 }
- 13 cout << "first x = " << x <<
- endl;
- 14 }
-
- The example produces the following output:
-
- second x = 2
- first x = 1
-
- Two variables named x are defined in main(). The definition of x on line 5
- retains storage throughout the execution of main(). Because the definition of x
- on line 10 occurs within a nested block, line 11 recognizes x as the variable
- defined on line 10. Line 13 is not part of the nested block. Thus, line 13
- recognizes x as the variable defined on line 5.
-
- When control exits from a block, all objects with destructors that are defined
- in the block are destroyed.
-
-
- ΓòÉΓòÉΓòÉ 7.4. Expression and Declaration Statements ΓòÉΓòÉΓòÉ
-
-
- ΓòÉΓòÉΓòÉ 7.4.1. Expression Statement ΓòÉΓòÉΓòÉ
-
- An expression statement evaluates the given expression. Expressions are
- described in "Expressions and Operators"
-
- The syntax is:
-
- expression-statement:
- [expression]
- ;
-
- Typically, an expression statement assigns the value of an expression to a
- variable or calls a function. For example:
-
- cout << "Account number:" << endl; //
- a call to cout
- marks = dollars * exch_rate; // an assignment
- to marks
- (difference < 0) ? ++losses : ++gain; // a conditional
- increment
- switches = flags | BIT_MASK; // an assignment
- to
- // switches
-
-
- ΓòÉΓòÉΓòÉ 7.4.2. Declaration Statement ΓòÉΓòÉΓòÉ
-
- A declaration statement introduces a new identifier into a block.
-
- The syntax is:
-
- declaration-statement:
- declaration
-
- When an identifier introduced by a declaration has previously been declared in
- an outer block, the outer declaration remains hidden in the inner block. In the
- following example, i has the value 100 before and after the for statement; the
- i within the for statement does not affect the i outside it.
-
- #include <iostream.h>
- void main()
- {
- int i=100;
- cout << i << endl;
- for ( int a=0 ; a<3 ; a++ )
- {
- int i;
- i = a + 5;
- cout << i << endl;
- }
- cout << i << endl;
- }
-
- This program generates the following output:
-
- 100
- 5
- 6
- 7
- 100
-
- auto and register variables are initialized each time the declaration
- statement containing them is executed. Local variables declared in a block are
- destroyed on exit from that block. auto variables defined in a loop are
- destroyed at each iteration. For example:
-
- class A { /* ... */ };
- for (int a=0; a<3; a++)
- {
- A myobj;
- }
-
- In this example, myobj is an auto variable because it has a block scope
- definition. Because of this, myobj is created and destroyed at each iteration
- of the loop.
-
- As long as you do not jump past a declaration with an initializer you can
- transfer into a block. If the declaration is in an inner block that is not
- entered or if the variable has already been initialized before the jump, this
- restriction does not apply. For example:
-
- class X { /* ... */ };
- void func()
- {
- goto skip1; // error - skipped over p and myobject
- init.
- noskip:
- X myobject(1);
- int p=3;
- return;
- skip1:
- goto noskip;
- X yourobject(myobject);
- }
-
- A static local object is initialized only once, when control passes through
- its declaration for the first time. A static variable initialized with an
- expression other than a constant expression is initialized to 0 before its
- block is first entered.
-
- The destructor for a static local object is called only if the object was
- constructed. The destructor must be called before or as part of the atexit()
- function. The atexit() function allows you to specify a function to which
- control can be passed at program termination. It is defined in the standard C
- header file <stdlib.h>.
-
- For further details, see "Constructors and Destructors".
-
-
- ΓòÉΓòÉΓòÉ 7.4.3. Ambiguity Resolution ΓòÉΓòÉΓòÉ
-
- There are situations where a statement can be parsed as both a declaration and
- as an expression. Specifically, a function declaration can look like a function
- call in certain cases. The compiler resolves these ambiguities by applying the
- following rules:
-
- o If the statement can be parsed as a declaration but there are no
- decl-specifiers in the declaration and the statement is inside the body of a
- function, the statement is assumed to be an expression. The following
- statement, for example is a declaration at file scope of the function f()
- that returns type int. There is no decl-specifier and int is the default,
- but at function scope this is a call to f():
-
- f();
-
- o If the statement can be parsed as a declaration up to the end of the first
- declarator, it is assumed to be a declaration even if subsequent parsing
- reveals that the statement is only valid as an expression. The following
- statement, for example, looks like a declaration with a syntax error at + +.
- Because it is a valid declaration for the first declarator (x), this
- statement is parsed as a declaration even though it could be parsed as a
- valid expression:
-
- int (x), y++;
-
- o In every other case, if the statement can be parsed as a declaration, it is
- assumed to be a declaration. The following statement, for example, is a
- declaration of x with redundant parentheses around the declarator, not a
- function-style cast of x to type int:
-
- int (x);
-
- In some cases the C++ grammar does not disambiguate between expression
- statements and declaration statements. The ambiguity arises when an expression
- statement has a function-style cast as its leftmost subexpression. In some
- cases, the ambiguity can be resolved by examining the entire statement
- containing the expression or declaration. If the statement can be interpreted
- both as a declaration and as an expression, the statement is interpreted as a
- declaration statement.
-
- The following expressions disambiguate into expression statements because the
- ambiguous subexpression is followed by an assignment or an operator. T in the
- expressions can be any type specifier:
-
- T(i)++;
- T(i,3)<<d;
- T(i)->l=24;
-
- In the following examples, the ambiguity cannot be resolved so the statements
- are interpreted as declarations. T is any type specifier:
-
- T(*i)(int);
- T(j)[5];
- T(*k) (float(3));
-
- The last statement above causes a compile-time error because you cannot
- initialize a pointer with a float value.
-
- Any statement whose ambiguity is not resolved by the above rules is by default
- a declaration statement. All of the following are declaration statements:
-
- T(a);
- T(*b)();
- T(c)=23;
- T(d),e,f,g=0;
- T(h)(e,3);
-
- The ambiguity is resolved only on a syntactic level. The disambiguation does
- not use the meaning of the names, except to assess whether or not they are type
- names.
-
- Another C++ ambiguity between expression statements and declaration statements
- is resolved by requiring a type name for function declarations within a block:
-
- a(); // declaration of a function returning int
- and
- // taking no arguments
- void func()
- {
- int a(); // declaration of a function
- int b; // declaration of a variable
- a(); // expression-statement calling function a()
- b; // expression-statement referring to a
- variable
- }
-
- The last statement above does not produce any action. It is semantically
- equivalent to a null statement. However it is a valid C++ statement.
-
-
- ΓòÉΓòÉΓòÉ 7.5. Selection Statements ΓòÉΓòÉΓòÉ
-
- A selection statement is used to control program flow.
-
- The syntax is:
-
- selection-statement:
- if (
- expression
- ) statement
- if (
- expression
- ) statement else
- statement
- switch (
- expression ) statement
-
- Each selection statement defines a local scope. A variable defined in the
- statement passes out of scope once control passes out of the selection
- statement. For example:
-
- if (tries <= max)
- for (int i = tries ; ; ) { /* ... */ }
-
- is equivalent to:
-
- if (tries <= max)
- {
- for (int i = tries ; ; ) { /* ... */ }
- }
-
- In either of the above, i passes out of scope after the if statement.
-
-
- ΓòÉΓòÉΓòÉ 7.5.1. if ΓòÉΓòÉΓòÉ
-
- An if statement allows you to process a statement on the condition that the
- specified test expression evaluates to a nonzero value. The expression must
- evaluate to an integral type, or a type that can be converted to an integral
- type. You can optionally specify an else clause for the if statement. If the
- test expression evaluates to 0 (zero), and an else clause exists, the statement
- in the else clause is performed. If the test expression evaluates to a nonzero
- value, the statement following the expression is performed and the else clause
- is ignored.
-
- When if statements are nested and else clauses are present, a given else is
- associated with the closest preceding if statement within the same block.
-
- The following example causes grade to receive the value A if the value of score
- is greater than or equal to 90.
-
- if (score >= 90)
- grade = 'A';
-
- The following example prints "Number is positive" to standard output if the
- value of score is greater or equal to 0 (zero). Otherwise, the example prints
- "Number is negative".
-
- if (number >= 0)
- cout << "Number is positive" << endl;
- else
- cout << "Number is negative" << endl;
-
- The following example shows a nested if statement:
-
- if (paygrade == 7)
- if (level >= 0 && level <=8)
- salary *= 1.05;
- else
- salary *= 1.04;
- else
- salary *= 1.06;
- cout << "Salary is " << salary <<
- endl;
-
- The following example shows a nested if statement that does not have an else
- clause. Because an else clause always associates with the closest if statement,
- you may need to use braces to force a particular else clause to associate with
- the correct if statement. In this example, omitting the braces would cause the
- else clause to associate with the nested if statement.
-
- if (gallons > 0)
- {
- if (miles > gallons)
- mpg = miles/gallons;
- }
- else
- mpg = 0;
-
- The following example shows an if statement nested within an else clause. This
- example tests multiple conditions. The tests are made in order of their
- appearance. If one test evaluates to a nonzero value, an action statement runs
- and the entire if statement ends.
-
- if (value > 0)
- ++increase;
- else if (value == 0)
- ++break_even;
- else
- ++decrease;
-
-
- ΓòÉΓòÉΓòÉ 7.5.2. switch ΓòÉΓòÉΓòÉ
-
- A switch statement enables you to transfer control to different statements
- within the switch body depending on the value of the switch expression. The
- body of the switch statement contains case labels to which execution is
- transferred if the switch expression evaluates to the given value. The switch
- expression must evaluate to an integral type. If none of the values matches and
- there is a default label, control is transferred to the default label. If none
- of the values matches and there is no default label, control is transferred to
- the first statement immediately following the switch. The value of each case
- expression must represent a different value. Only one default label can occur
- in each switch statement.
-
- The switch statement passes control to the statement following one of the case
- labels or to the statement following the switch body. The value of the
- expression that precedes the switch body determines the statement that receives
- control. This expression is called the switch expression.
-
- If control passes to a statement in the switch body, control does not pass from
- the switch body to the statement directly following the switch body until a
- break statement is encountered or until the last statement in the switch body
- is processed.
-
- If necessary, a conversion to integer is performed on the controlling
- expression, and all expressions in the case statements are converted to the
- same type as the controlling expression.
-
- You can have declarations in the body of the switch statement. You cannot
- transfer control over a declaration containing an initializer, unless the
- declaration is located in an inner block that is completely bypassed by the
- transfer of control. All declarations within the body of the switch statement
- that contain initializers must be contained in an inner block.
-
- The following switch statement contains several case clauses and one default
- clause. Each clause contains a function call and a break statement. The break
- statements prevent control from passing down through each statement in the
- switch body. For instance, if the switch expression evaluates to '/', the
- switch statement calls the function divide. Control then passes to the
- statement following the switch body.
-
- char key;
- cout << "Enter an arithmetic operator\n";
- cin >> key
- switch (key)
- {
- case '+':
- add();
- break;
- case '-':
- subtract();
- break;
- case '*':
- multiply();
- break;
- case '/':
- divide();
- break;
- default:
- cout << "The key you pressed is not valid\n";
- break;
- } // end of switch body
-
- If the switch expression matches a case expression, the statements following
- the case expression are processed until a break statement is encountered or
- until the end of the switch body is reached. In the following example, break
- statements are not present. If the value of text is equal to 'A', all three
- counters are incremented. If the value of text is equal to 'a', lettera and
- total are increased. If text is not equal to 'A' or 'a', only total is
- increased.
-
- int capa=0, lettera=0, total=0, i;
- char text[100];
- for (i=0; i<sizeof(text); i++)
- {
- // Switch statement with no break statements
- switch (text[i])
- {
- case 'A': // No break statement - 'A' increments
- all of
- capa++; // capa, lettera and total
- case 'a': // No break statement - 'a' increments
- both
- lettera++; // lettera and total
- default:
- total++;
- }
- }
-
- The following switch statement executes the same statements for more than one
- case label:
-
- int month;
- switch (month)
- {
- case 12:
- case 1:
- case 2:
- cout << "month " << month <<
- " is a winter month" << endl;
- break;
- case 3:
- case 4:
- case 5:
- cout << "month " << month <<
- " is a spring month" << endl;
- break;
- case 6:
- case 7:
- case 8:
- cout << "month " << month <<
- " is a summer month" << endl;
- break;
- case 9:
- case 10:
- case 11:
- cout << "month " << month <<
- " is a fall month" << endl;
- break;
-
- default:
- cout << "not a valid month" << endl;
- break;
- } // end of switch body
-
- If the expression month has the value 3, control passes to the statement:
-
- cout << "month " << month << "
- is a spring month" << endl;
-
- The break statement then passes control to the statement following the switch
- body. For more details, see "break"
-
-
- ΓòÉΓòÉΓòÉ 7.6. Iteration Statements ΓòÉΓòÉΓòÉ
-
- An iteration statement specifies that the statement or block following it is to
- be repeated until the condition is met.
-
- The syntax is:
-
- iteration-statement:
- while (
- expression ) statement
- do statement
- while
- ( expression )
- ;
- for ( for-init-statement
- [expression]
- ;
- [expression]
- ) statement
-
- for-init-statement:
- expression-statement
- declaration-statement
-
- The statement of an iteration-statement defines a local scope. A variable
- defined in the statement passes out of scope once control passes out of the
- iteration statement. For example,
-
- while (tries <= max)
- for (int i = tries ; ; ) { /* ... */ }
-
- is equivalent to:
-
- while (tries <= max)
- {
- for (int i = tries ; ; ) { /* ... */ }
- }
-
- In either of the above, i passes out of scope after the while statement.
-
-
- ΓòÉΓòÉΓòÉ 7.6.1. while ΓòÉΓòÉΓòÉ
-
- A while statement enables you to repeatedly run the body of a loop until the
- controlling expression evaluates to zero.
-
- The expression is evaluated to determine whether or not the body of the loop is
- processed. The expression must be convertible to a scalar type. If the
- expression evaluates to zero, the body of the loop never runs. If the
- expression evaluates to nonzero, the body is processed. After the body has run,
- control passes back to the expression. Further processing depends on the value
- of the condition.
-
- A break, return, or goto statement can cause the processing of a while
- statement to end, even when the condition does not evaluate to 0.
-
- In the following program, item[index] triples each time the value of the
- expression ++index is less than MAX_INDEX. When index evaluates to MAX_INDEX,
- the while statement ends.
-
- #include <iostream.h>
- void main()
- {
- int item[5] = { 12, 55, 62, 85, 102 };
- int index = 0;
- const MAX_INDEX = 5;
- while (index < MAX_INDEX)
- {
- item[index] *= 3;
- cout << "item " << index <<
- " = " << item[index] << endl;
- ++index;
- }
- }
-
- For more details, see "break" , "continue" , "return" , and "goto"
-
-
- ΓòÉΓòÉΓòÉ 7.6.2. do ΓòÉΓòÉΓòÉ
-
- A do statement repeatedly executes a statement until a test expression
- evaluates to 0. Because of this order of processing, the statement is processed
- at least once.
-
- The body of the loop is run before the controlling while clause is evaluated.
- Further processing of the do statement depends on the value of the while
- clause. If the while clause does not evaluate to 0, the statement runs again.
- Otherwise, processing of the statement ends. The controlling expression must
- evaluate to a scalar type.
-
- A break, return, goto, or continue statement can cause the processing of a do
- statement to end, even when the while clause does not evaluate to 0.
-
- The following example prompts the user to enter a 1. If the user does, the do
- statement ends execution. If the user does not, the statement displays another
- prompt. The example contains error-checking code to verify that the user
- entered an integer value and to clear the input stream if an error occurs.
-
- #include <iostream.h>
- void main()
- {
- int reply1;
- char c;
- do
- {
- cout << "Enter a 1: ";
- cin >> reply1;
- if (cin.fail())
- {
- cerr << "Not a valid number." <<
- endl;
- // Clear the error flag.
- cin.clear(cin.rdstate() & ~ios::failbit);
- // Purge garbage input.
- cin.ignore(cin.rdbuf()->in_avail());
- }
- }
- while (reply1 != 1);
- }
-
- For more details, see "break" , "return" , and "goto"
-
-
- ΓòÉΓòÉΓòÉ 7.6.3. for ΓòÉΓòÉΓòÉ
-
- A for statement has the following syntax:
-
- for ( for-init-statement
- [expression]
- ;
- [expression]
- )
- statement
-
- A for statement enables you to:
-
- o Evaluate a for-init-statement prior to the first iteration of the statement
- (initialization)
-
- o Specify an expression to determine whether or not the statement should be
- processed (controlling part)
-
- o Evaluate an expression after each iteration of the statement
-
- o Process the statement if the controlling part does not evaluate to zero.
-
- For a statement of the form:
-
- for (state1; exp2; exp3) statement
-
- state1 is evaluated only before the statement is processed for the first
- time. You can use this statement to declare and initialize a
- variable. If you declare a variable in state1, the variable has the
- same scope as the for statement and is not local to the for
- statement. If you do not want to execute this statement prior to the
- first iteration of the for statement, you can omit state1.
-
- exp2 is evaluated before each iteration of the statement. The expression
- must evaluate to a scalar type. If it evaluates to 0 (zero), the
- statement is not processed and control moves to the next statement
- following the for statement. If exp2 does not evaluate to 0, the
- statement is processed. If you omit exp2, it is as if the expression
- had been replaced by a nonzero constant and the for statement is not
- terminated by failure of this condition.
-
- exp3 is evaluated after each execution of the statement. You can use this
- expression to increase, decrease, or reinitialize a variable. If you
- do not want to evaluate an expression after each iteration of the
- statement, you can omit this expression.
-
- A break, return, or goto statement can cause the processing of a for statement
- to end, even when the second expression does not evaluate to 0 (zero). If you
- omit exp2, you should use a break, return, or goto statement to stop the for
- statement from running.
-
- The following for statement prints the value of count 20 times. The for
- statement initially sets the value of count to 1. After each iteration of the
- statement, count is incremented.
-
- for (count = 1; count <= 20; count++)
- cout << "count = " << count <<
- endl;
-
- The following sequence of statements accomplishes the same task. Note the use
- of the while statement instead of the for statement.
-
- int count = 1;
- while (count <= 20)
- {
- cout << "count = " << count <<
- endl;
- count++;
- }
-
- The following for statement does not contain an initialization expression.
-
- int index = 20;
- for (; index > 10; --index)
- {
- list[index] = var1 + var2;
- cout << "list " << index << "
- = " << list[index] << endl;
- }
-
- The following for statement iterates until cin receives the letter e:
-
- char letter;
- // .
- // .
- // .
- for (;;)
- {
- cin >> letter;
- if (letter == 'e')
- break;
- cout << "You entered the letter " <<
- letter << endl;
- }
-
- The following for statement contains compound initializations and increments.
- The first comma in the for expression is a punctuator for a declaration; that
- is, it declares and initializes two integers, i and j. The second comma, a
- comma operator, allows both i and j to be incremented at each step through the
- loop.
-
- for (int i = 0, j = 50; i < 10; ++i, j += 50)
- {
- cout << "i = " << i << " and
- j = " << j << endl;
- }
-
- The following example shows a nested for statement. The outer statement is
- performed as long as the value of row is less than 5. Each time the outer for
- statement is processed, the inner for statement sets the initial value of
- column to zero and the statement of the inner for statement is run three times.
- The inner statement is run as long as the value of column is less than 3. This
- example prints the values of a 5 by 3 array in a 5 row by 3 column table:
-
- for (row = 0; row < 5; row++)
- {
- for (column = 0; column < 3; column++)
- cout << table[row][column] <<
- " ";
- cout endl;
- }
-
- For more details, see "break" , "continue" , and "Comma Operator"
-
-
- ΓòÉΓòÉΓòÉ 7.7. Jump Statements ΓòÉΓòÉΓòÉ
-
- Jump statements transfer control unconditionally.
-
- The syntax is:
-
- jump-statement:
- break ;
- continue ;
- return[expression]
- ;
- goto identifier ;
-
-
- ΓòÉΓòÉΓòÉ 7.7.1. break ΓòÉΓòÉΓòÉ
-
- A break statement enables you to end an iterative (do, for, while) or switch
- statement and exit from it at any point other than the logical end.
-
- In an iterative statement, the break statement ends the loop and moves control
- to the next statement outside the iterative statement. In a switch body, the
- break statement ends the processing of the switch body and gives control to the
- statement after the switch statement. Within nested statements, the break
- statement ends only the nearest enclosing do, for, switch, or while statement.
-
- You should place a break statement only in the body of an iterative statement
- or in the body of a switch statement.
-
- The following example shows a break statement in a for statement. If the i th
- element of the array string is equal to '\0', the break statement causes the
- for statement to end.
-
- for (i = 0; i < 5; i++)
- {
- if (string[i] == '\0')
- break;
- length++;
- }
-
- The following example shows a break statement in a nested iterative statement.
- The outer loop goes through an array of pointers to strings. The inner loop
- examines each character of the string. When the break statement is processed,
- the inner loop ends and control returns to the outer loop.
-
- /**************************************************************
- ** This program counts the characters in the strings that
- **
- ** are part of an array of pointers to characters.
- **
- ** The count stops when one of the digits 0 (zero)
- **
- ** through 9 is encountered and resumes at the beginning
- **
- ** of the next string.
- */
- #include <iostream.h>
- void main()
- {
- static char *strings[3] = { "ab", "c5d",
- "e5" };
- int letter_count = 0;
- for (int i=0; i<3; i++) // for each
- string
- { // for each
- character
- for (char *pointer=strings[i]; *pointer !=
- '\0';++pointer)
- {
- // if a number
- if (*pointer >= '0' && *pointer <=
- '9')
- break;
- letter_count++;
- }
- cout << "Letter count = " <<
- letter_count << endl;
- }
- }
-
- The program produces the following output:
-
- Letter count = 4
-
- The following example is a switch statement that contains several break
- statements. Each break statement indicates the end of a specific clause and
- ends the processing of the switch statement.
-
- switch (timeofday)
- {
- case (morning):
- cout << "Good Morning\n";
- break;
- case (evening):
- cout << "Good Evening\n";
- break;
- default:
- cout << "Good Day\n";
- break;
- }
-
- For more details, see "switch" , "while" , "do" , and "for"
-
-
- ΓòÉΓòÉΓòÉ 7.7.2. continue ΓòÉΓòÉΓòÉ
-
- A continue statement enables you to stop the current iteration of a loop.
- Program control is passed from the continue statement to the condition part of
- the loop. You can only have a continue statement in an iterative statement.
-
- The continue statement ends the execution of the action part of a do, for, or
- while statement and moves control to the condition part of the statement. If
- the iterative statement is a for statement, control moves to the third
- expression in the condition part of the statement, and then to the second
- expression (the test) in the condition part of the statement. Within nested
- statements, the continue statement ends only the current iteration of the do,
- for, or while statement immediately enclosing it.
-
- The following example shows a continue statement in a for statement. The
- continue statement causes the system to skip over those elements of the integer
- array rates that have values less than or equal to 1.
-
- #include <iostream.h>
- void main()
- {
- static float rates[5] = { 1.45, 0.05, 1.88,
- 2.03,
- 0.75 };
- cout << "Rates over 1.00\n";
- for (int i = 0; i < 5; i++)
- {
- if (rates[i] <= 1.00) /* skip rates
- <= 1.00 */
- continue;
- cout << "rate = " << rates[i]
- << endl;
- }
- }
-
- The program produces the following output:
-
- Rates over 1.00
- rate = 1.45
- rate = 1.88
- rate = 2.03
-
- The following example shows a continue statement in a nested loop. When the
- inner loop encounters a number in the array strings, that iteration of the loop
- is stopped. Processing continues with the third expression of the inner loop.
- The inner loop is ended when the '\0' escape sequence is encountered.
-
- /**************************************************************
- ** This program counts the characters in strings that
- **
- ** are part of an array of pointers to characters.
- **
- ** The count excludes the digits 0 (zero) through 9.
- **
- **************************************************************/
- #include <iostream.h>
- void main()
- {
- static char *strings[3] = { "ab", "c5d",
- "e5" };
- int letter_count = 0;
- for (int i = 0; i < 3; i++) // for each string
- // for each each character
- for (char *pointer = strings[i]; *pointer !=
- '\0';
- ++pointer)
- { // if a number
- if (*pointer >= '0' && *pointer <= '9')
- continue;
- letter_count++;
- }
- cout << "letter count = " << letter_count
- << endl;
- }
-
- The program produces the following output:
-
- letter count = 5
-
- For more details, see "while" , "do" , and "for"
-
-
- ΓòÉΓòÉΓòÉ 7.7.3. return ΓòÉΓòÉΓòÉ
-
- A return statement ends the execution of the current function and returns
- control to the caller of the function.
-
- A return statement in a function is optional. The &xcomp. &xcompos2. issues a
- warning if a return statement is not found in a function declared with a return
- type. If the end of a function is reached without encountering a return
- statement, control is passed to the caller as if a return statement without an
- expression were encountered. A function can contain multiple return statements.
-
- If an expression is present on a return statement, the value of the expression
- is returned to the caller. If the data type of the expression is different from
- the function return type, conversion of the return value takes place as if the
- value of the expression were used to initialize an object with the same
- function return type.
-
- If an expression is not present in a return statement, the value of the return
- statement is undefined. If the function is declared with a nonvoid return type
- a warning is generated, and the result of calling the function is
- unpredictable. For example,
-
- #include <iostream.h>
- int func1() {
- return;
- }
- int func2() {
- return (4321);
- }
-
- void main() {
- int a=func1(); // result unpredictable!
- int b=func2();
- }
-
- You cannot use a return statement in an expression when the function is
- declared as returning type void.
-
- If a function returns a class object with constructors, a temporary class
- object may be constructed. The temporary object is not in the scope of the
- function returning the temporary object but is local to the caller of the
- function.
-
- When a function returns, all temporary local variables are destroyed. If local
- class objects with destructors exist, destructors are called. For more details,
- see "Temporary Objects"
-
- The following function searches through an array of integers to determine if a
- match exists for the variable number. If a match exists, the function match
- returns the value of i. If a match does not exist, the function match returns
- the value -1.
-
- int match(int number, int array[], int n)
- {
- int i;
- for (i = 0; i < n; i++)
- if (number == array[i])
- return (i);
- return(-1);
- }
-
- For more details, see "Chapter 8. Functions" , and specifically "Return Values"
- , and specifically "Return Values"
-
-
- ΓòÉΓòÉΓòÉ 7.7.4. goto ΓòÉΓòÉΓòÉ
-
- A goto statement causes your program to unconditionally transfer control to the
- statement associated with the label specified on the goto statement. The label
- must appear in the same function as the goto statement.
-
- Because the goto statement can interfere with the normal top-to-bottom sequence
- of processing, it makes a program more difficult to read and maintain. Often, a
- break statement, a continue statement, or a function call can eliminate the
- need for a goto statement.
-
- If you use a goto statement to transfer control to a statement inside of a loop
- or block, initializations of automatic storage for the loop do not take place,
- and an error is generated.
-
- If an active block is exited using a goto statement, any local variables are
- destroyed when control is transferred from that block.
-
- The following example shows a goto statement that is used to jump out of a
- nested loop. This function could be written without using a goto statement.
-
- void display(int matrix[3][3])
- {
- int i, j;
- for (i = 0; i < 3; i++)
- {
- for (j = 0; j < 3; j++)
- {
- if ( (matrix[i][j] < 1) ||
- (matrix[i][j]
- > 6) )
- goto out_of_bounds;
- cout << "matrix " <<
- i << "," << j << " = "
- cout << matrix[i][j] <<
- endl;
- }
- }
- return;
- out_of_bounds: cout << "Number must be 1 through
- 6" << endl;
- }
-
-
- ΓòÉΓòÉΓòÉ 7.8. Null Statement ΓòÉΓòÉΓòÉ
-
- The null statement performs no operation.
-
- A null statement can hold the label of a labeled statement or show a
- nonexistent action in an iterative (do, for, while) statement.
-
- The following example initializes the elements of the array price:
-
- for (i = 0; i < 3; price[i++] = 0)
- ; // null statement
-
- Because the initializations occur in the for expressions, a statement is only
- needed to complete the for syntax; no operations are required.
-
-
- ΓòÉΓòÉΓòÉ 7.9. Related Information ΓòÉΓòÉΓòÉ
-
- "Expressions and Operators"
-
-
- ΓòÉΓòÉΓòÉ 8. Chapter 8. Functions ΓòÉΓòÉΓòÉ
-
- This chapter describes the structure and use of functions in C++. The
- following features of C++ functions are described in this chapter:
-
- o Introduction to Functions
- o C++ enhancements to C functions
- o Function declarations
- o Function definitions
- o The main() Function
- o Calling functions and argument passing
- o Default arguments
- o Return values
- o Pointers to functions
- o Inline functions
- o Special C++ functions.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 8.1. Introduction to Functions ΓòÉΓòÉΓòÉ
-
- Functions specify the logical structure of a program and define how particular
- operations are to be implemented. A function declaration consists of a return
- type, a name, and an argument list. It is used to declare the format and
- existence of a function prior to its use. C++ uses the style of declaration
- called prototyping. A prototype refers to the return type, name, and argument
- list components of a function. It is used by the &xcomp. &xcompos2. for
- argument type checking and argument conversions. Prototypes can appear several
- times in a program provided the declarations are compatible. A function
- definition contains a function declaration and the body of the function. A
- function can only have one definition. Function prototypes are usually placed
- in header files, while function definitions appear in source files.
-
-
- ΓòÉΓòÉΓòÉ 8.2. C++ Enhancements to C Functions ΓòÉΓòÉΓòÉ
-
- The C++ language provides many enhancements to C functions. These are:
-
- o Default arguments
-
- o Reference arguments
-
- o Reference return types
-
- o Inline functions
-
- o Member functions
-
- o Overloaded functions
-
- o Operator functions
-
- o Constructor and destructor functions
-
- o Conversion functions
-
- o Virtual functions
-
- o Function templates.
-
-
- ΓòÉΓòÉΓòÉ 8.3. Function Declarations ΓòÉΓòÉΓòÉ
-
- A function declaration gives the return type of the function, the function
- name, and the number and type of the arguments that must be passed to the
- function when the function is called. You can specify the qualifiers volatile
- and const in member function declarations. You can also specify exception
- specifications in function declarations. Functions must be declared before they
- can be called.
-
- Types cannot be defined in return or argument types. For example, the following
- declarations are not valid in C++ :
-
- void print(struct X { int i;} x); //error
- enum count{one, two, three} counter(); //error
-
- This example attempts to declare a function print() that takes an object x of
- class X as its argument. However the class definition is not allowed within the
- argument list. In the attempt to declare counter(), the enumeration type
- definition cannot appear in the return type of the function declaration. The
- two function declarations and their corresponding type definitions can be
- rewritten as follows:
-
- struct X { int i;};
- void print(X x);
- enum count {one, two, three};
- count counter();
-
-
- ΓòÉΓòÉΓòÉ 8.3.1. Function Declaration Grammar ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- decl-specifier declarator
-
- where declarator has the form:
-
- declarator (
- argument-declaration-list
- ) [cv-qualifier]
- [exception-specification]
-
- and argument-declaration-list has the form:
-
- argument-declaration-list:
- [arg-declaration-list]
- [...]
- [arg-declaration-list] , ...
-
- arg-declaration-list:
- argument-declaration
- arg-declaration-list ,
- argument-declaration
- argument-declaration:
- decl-specifiers declarator
- decl-specifiers declarator =
- expression
- decl-specifiers
- [abstract-declarator]
- decl-specifiers
- [abstract-declarator]
- = expression
-
- The complete syntax for declarators is given in "Declaration Grammar"
-
- cv-qualifiers are described in "volatile and const Attributes" and
- exception-specifications are described in "Exception Specifications"
-
- An ellipsis at the end of an argument-declaration-list indicates that the
- number of arguments is equal to, or greater than, the number of specified
- argument types. Where it is permitted, an ellipsis preceded by a comma is
- equivalent to a simple ellipsis.
-
- An empty argument declaration list or the argument declaration list of (void)
- indicates a function that takes no arguments. void cannot be used as an
- argument type, although types derived from void (such as pointers to void) can
- be used.
-
- The default return type of a function is int.
-
-
- ΓòÉΓòÉΓòÉ 8.3.2. Multiple Function Declarations ΓòÉΓòÉΓòÉ
-
- All function declarations for a particular function must have the same number
- and type of arguments, and must have the same return type. These return and
- argument types are part of the function type, although the default arguments
- are not. The ellipsis is considered a part of the function type. If the only
- difference between the argument types in two declarations is in the use of
- typedef names or unspecified argument array bounds, the declarations are the
- same. A cv-qualifier is also part of the function type, but can only be part of
- a declaration or definition of a nonstatic member function.
-
- If you declare two functions differing only in return type, it is not valid
- function overloading and is flagged as an error. For example:
-
- void f();
- int f(); // error, two definitions differ only in
- // return type
- int g()
- {
- return f();
- }
-
-
- ΓòÉΓòÉΓòÉ 8.3.3. Checking Function Calls ΓòÉΓòÉΓòÉ
-
- The &xcomp. &xcompos2. checks function calls by comparing the number and type
- of the actual arguments used in the function call with the number and type of
- the formal arguments in the function declaration. Implicit type conversion is
- performed when necessary.
-
-
- ΓòÉΓòÉΓòÉ 8.3.4. Argument Names in Function Declarations ΓòÉΓòÉΓòÉ
-
- You can supply argument names in a function declaration but the &xcomp.
- &xcompos2. ignores them except in the following two situations:
-
- 1. If two argument names have the same name within a single declaration. This
- is an error.
-
- 2. If an argument name is the same as a name outside the function. In this
- case the name outside the function is hidden and cannot be used in the
- argument declaration. In the following example, it is intended that the
- third argument intersects has enumeration type subway_line, but this name
- is hidden by the name of the first argument. The declaration of the
- function subway() causes a compile-time error because subway_line is not a
- valid type name in the context of the argument declarations.
-
- enum subway_line {yonge, university, spadina,
- bloor};
- int subway(char * subway_line, int stations,
- subway_line intersects);
-
-
- ΓòÉΓòÉΓòÉ 8.3.5. Examples of Functions Declarations ΓòÉΓòÉΓòÉ
-
- You can declare a function with no arguments in two ways:
-
- int f(void); // ANSI C Standard
-
- or
-
- int f(); // C++ enhancement
-
- A function can also be declared with a variable number of arguments. To declare
- this type of function, use an ellipsis in the argument list in the function
- declaration as shown in the following example,
-
- int f(int,...);
-
- Note: The comma before the ellipsis in the above declaration is optional.
-
- No type checking is performed on the variable arguments.
-
- The following code fragments show several function declarations. The first
- declares a function f that takes two integer arguments and has a return type of
- void:
-
- void f(int, int);
-
- The following fragment declares a function f1 that takes an integer argument,
- and returns a pointer to a function that takes an integer argument and returns
- an integer:
-
- int (*f1(int))(int);
-
- Alternatively, a typedef can be used for the complicated return type of
- function f1:
-
- typedef int pf1(int);
- pf1* f1(int);
-
- The following fragment declares a pointer p1 to a function that takes a pointer
- to a constant character and returns an integer:
-
- int (*p1) (const char*);
-
- The following declaration is of an external function f2 that takes a constant
- integer as its first argument, can have a variable number and variable types of
- other arguments, and returns type int.
-
- int extern f2(const int ...);
-
- Function f3 takes an int argument with a default value that is the value
- returned from function f2, and that has a return type of int:
-
- const int j = 5;
- int f3( int x = f2(j) );
-
- Function f6 is a constant class member function of class X with no arguments,
- and with an int return type:
-
- class X
- {
- public:
- int f6() const;
- };
-
- Function f4 takes no arguments, has return type void, and can throw class
- objects of types X and Y.
-
- class X;
- class Y;
- // .
- // .
- // .
- void f4() throw(X,Y);
-
- Function f5 takes no arguments, has return type void and cannot throw an
- exception.
-
- void f5() throw();
-
- See "Exception Specifications" for more details on throw().
-
-
- ΓòÉΓòÉΓòÉ 8.4. Function Definitions ΓòÉΓòÉΓòÉ
-
- Every function that is called must be defined exactly once in a program. A
- function definition is composed of the declaration and the body of the
- function.
-
-
- ΓòÉΓòÉΓòÉ 8.4.1. Function Definition Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for a function definition is the same as for a declaration except
- that the declaration is followed by the function body.
-
- function-definition:
- [decl-specifiers]
- declarator
- [ctor-initializer]
- fct-body
- fct-body:
- compound-statement
-
- where fct-body (function body) is a compound statement. For further details,
- see "Compound Statements"
-
- The following example shows a function declaration and definition:
-
- #include<math.h>
- extern double root(double value, double base); // declaration
- .
- .
- .
- double root(double value, double base) // definition
- {
- double temp = exp(log(value)/base);
- return temp;
- }
-
- The argument names value and base are optional in the declaration. If the two
- arguments have the same name, an error occurs. If an argument name is the same
- as a name outside the function, the outside name is hidden. See "Argument Names
- in Function Declarations" for more details.
-
-
- ΓòÉΓòÉΓòÉ 8.5. The main() Function ΓòÉΓòÉΓòÉ
-
- Every program must have exactly one external function named main(). This
- function marks the entry point for the program. main() is extern by default.
- The return type for main() can be void or int. The default type is int. The
- function main() can be defined with or without arguments. These arguments pass
- program parameters and environment settings to the program, and are discussed
- in Appendix C.
-
- You cannot use the specifiers inline or static when declaring main(). You
- cannot call main() from within a program. You cannot take the address of
- main().
-
-
- ΓòÉΓòÉΓòÉ 8.6. Calling Functions and Argument Passing ΓòÉΓòÉΓòÉ
-
- A function is called by applying the function call operator ( ) to the name of
- the function. The actual arguments are placed inside the call operator. When a
- function is called, the actual arguments are used to initialize the formal
- arguments.
-
- The type of an actual argument is checked against the type of the corresponding
- formal argument in the function prototype. All standard and user-defined type
- conversions are applied as necessary. For example,
-
- #include<iostream.h>
- #include<math.h>
- extern double root(double, double); // declaration
- double root(double value, double base) // definition
- {
- double temp = exp(log(value)/base);
- return temp;
- }
- void main()
- {
- int value = 144;
- int base = 2;
- // Call function root and print return value
- cout << "The root is: " << root(value,base)
- << endl;
- }
-
- The output is The root is: 12
-
- In the above example, because the functionroot is expecting arguments of type
- double, the two int arguments value and base are implicitly converted to type
- double when the function is called.
-
-
- ΓòÉΓòÉΓòÉ 8.6.1. Passing Array Arguments to Functions ΓòÉΓòÉΓòÉ
-
- When a function argument is an array, it is converted to a pointer to the first
- element of the array. An array cannot be passed by value to a function. Any
- assignment to an element of the array within the function modifies the actual
- value of the element.
-
-
- ΓòÉΓòÉΓòÉ 8.6.2. Passing Function Arguments to Functions ΓòÉΓòÉΓòÉ
-
- When a function argument is itself a function, it is converted to a pointer to
- the function. When a function argument is a nonstatic member function, it is
- converted to a pointer to member.
-
-
- ΓòÉΓòÉΓòÉ 8.6.3. Passing Class Arguments to Functions ΓòÉΓòÉΓòÉ
-
- It is an error when a function argument is a class and all of the following
- properties hold:
-
- o The class needs a copy constructor
-
- o The class does not have a user defined copy constructor
-
- o A copy constructor cannot be generated for that class.
-
-
- ΓòÉΓòÉΓòÉ 8.6.4. Passing Arguments by Reference ΓòÉΓòÉΓòÉ
-
- If you use a reference type as a formal argument, you can make a
- pass-by-reference call to a function. In a pass-by-reference call, the values
- of arguments in the calling function can be modified in the called function. In
- pass-by-value calls, only copies of the arguments are passed to the function.
-
- Note: The term pass by reference describes a general method of passing
- arguments from a calling routine to a called routine. The term reference in the
- context of C++ refers to a specific way of declaring objects and functions.
-
- The following example shows how arguments are passed by reference:
-
- #include <iostream.h>
- void swapnum(int &i, int &j)
- {
- // Note that reference formal arguments are initialized
- with
- // the actual arguments when the function is called
- //
- int temp = i;
- i = j;
- j = temp;
- }
- .
- .
- .
- main()
- {
- int a = 10, // a is 10
- b = 20; // b is 20
- swapnum(a,b); // now a is 20 and b is 10
- cout << "A is : " << a <<
- " and B is : " << b << endl;
- }
-
- When the function swapnum() is called the actual values of the variables a and
- b are exchanged because they are passed by reference. The output is:
-
- A is : 20 and B is : 10
-
- You must define the formal arguments of swapnum() as references if you want the
- values of the actual arguments to be modified by the function swapnum().
-
-
- ΓòÉΓòÉΓòÉ 8.6.5. Restrictions on Passing Arguments by Reference ΓòÉΓòÉΓòÉ
-
- There are two cases where attempting to pass arguments by reference causes the
- &xcomp. &xcompos2. to issue a warning for these cases:
-
- o If the last argument specified in the function declaration before the
- ellipsis is a reference argument, arguments passed using an ellipsis
- (variable arguments) are not accessible using the mechanism from the
- <stdarg.h> standard header file.
-
- o Ellipsis arguments cannot be passed as references.
-
- In addition to these restrictions, when the actual argument cannot be
- referenced directly by the formal argument, the compiler creates a temporary
- variable that is referenced by the formal argument and initialized using the
- value of the actual argument. In this case, the formal argument must be a
- const reference.
-
-
- ΓòÉΓòÉΓòÉ 8.6.6. Passing Arguments by Constant Reference ΓòÉΓòÉΓòÉ
-
- Reference arguments declared const can be used to pass large objects
- efficiently to functions without making a temporary copy of the object that is
- passed to the function. Because the reference is declared const, the actual
- arguments cannot be changed by the function. For example,
-
- void printbig (const bigvar&); // Function prototype
-
- When a function printbig is called, it cannot modify the object of type bigvar
- because the object was passed by constant reference.
-
-
- ΓòÉΓòÉΓòÉ 8.6.7. Passing Pointer Values to Functions ΓòÉΓòÉΓòÉ
-
- Pointers provide a way for a called function to alter the value of a variable
- accessible to the calling function. A called function receives a copy of the
- pointer value and can only alter the copy, not the value of the pointer in the
- calling function. However, the called function can alter the value of the
- variable that the pointer points to. , "References" , "Function Call" , and
- "Standard Conversions"
-
-
- ΓòÉΓòÉΓòÉ 8.7. Default Arguments ΓòÉΓòÉΓòÉ
-
- You can provide default values for function arguments. All default argument
- names of a function are bound when the function is declared. All functions
- have their types checked at declaration, and are evaluated at each point of
- call. For example,
-
- #include <iostream.h>
- int a=1;
- int f(int a) {return a;}
- int g(int x = f(a)) {return f(a);}
- int h()
- {
- a=2;
- {
- int a = 3;
- return g();
- }
- }
- main()
- {
- cout << h() << endl;
- }
-
- This example prints "2" to standard output, because the value of a is
- determined after entry into function h() but before the call to g() is
- resolved.
-
- A default argument can have any type.
-
- A pointer to a function must have the same type as the function. Attempts to
- take the address of a function by reference without specifying the type of the
- function produce an error. The type of a function is not affected by arguments
- with default values.
-
- The following example shows that the fact that a function has default arguments
- does not change its type. The default argument allows you to call a function
- without specifying all of the arguments, it does not allow you to create a
- pointer to the function that does not specify the types of all the arguments.
- Thus, f can be called without an explicit argument, but the pointer badpointer
- cannot be defined without specifying the type of the argument.
-
- int f(int = 0);
- void g()
- {
- int a = f(1); // ok
- int b = f(); // ok, default argument
- used
- }
- int (*pointer)(int) = &f; // ok, type of f() specified
- (int)
- int (*badpointer)() = &f; // error, badpointer and
- f have
- // different types. badpointer
- must
- // be initialized with a pointer
- to
- // a function taking no arguments.
-
-
- ΓòÉΓòÉΓòÉ 8.7.1. Restrictions on Default Arguments ΓòÉΓòÉΓòÉ
-
- Of the operators, only the function call operator and the operator new can have
- default arguments when they are overloaded.
-
- Arguments with default values must be the trailing arguments in the function
- declaration argument list. For example:
-
- void f(int a, int b = 2, int c = 3); // trailing defaults
- void g(int a = 1, int b = 2, int c); // error, leading
- defaults
- void h(int a, int b = 3, int c); // error, default
- in middle
-
- Once a default argument has been given in a declaration or definition, you
- cannot redefine that argument, even to the same value. However you can add
- default arguments not given in previous declarations. For example, the last
- declaration below attempts to redefine the default values for a and b:
-
- void f(int a, int b, int c=1); // valid
- void f(int a, int b=1, int c); // valid, add another
- default
- void f(int a=1, int b, int c); // valid, add another
- default
- void f(int a=1, int b=1, int c=1); // error, redefined
- defaults
-
- You can supply any default argument values in the function declaration or in
- the definition. All subsequent arguments must have default arguments supplied
- in this or a previous declaration of the function.
-
- You cannot use local variables in default argument expressions. For example,
- the &xcomp. &xcompos2. generates errors for both function g() and function h()
- below:
-
- void f(int a)
- {
- int b=4;
- void g(int c=a); // Local variable "a" inaccessible
- void h(int d=b); // Local variable "b" inaccessible
- }
-
-
- ΓòÉΓòÉΓòÉ 8.7.2. Evaluating Default Arguments ΓòÉΓòÉΓòÉ
-
- When a function defined with default arguments is called with trailing
- arguments missing, the default expressions are evaluated. For example:
-
- void f(int a, int b = 2, int c = 3); // declaration
- // ...
- int a = 1;
- f(a); // same as call f(a,2,3)
- f(a,10); // same as call f(a,10,3)
- f(a,10,20); // no default arguments
-
- Default arguments are checked against the function declaration and evaluated
- when the function is called. The order of evaluation of default arguments is
- undefined. Default argument expressions cannot use formal arguments of a
- function. For example:
-
- int f(int q = 3, int r = q); // error
-
- The argument r cannot be initialized with the value of the argument q because
- the value of q may not be known when it is assigned to r. If the above function
- declaration is rewritten:
-
- int q=5;
- int f(int q = 3, int r = q); // error
-
- the value of r in the function declaration still produces an error because the
- variable q defined outside of the function is hidden by the argument q declared
- for the function. Similarly:
-
- typedef double D;
- int f(int D, int z = D(5.3) ); // error
-
- Here the type D is interpreted within the function declaration as the name of
- an integer. The type D is hidden by the argument D. The cast D(5.3) is
- therefore not interpreted as a cast because D is the name of the argument not a
- type.
-
- In the following example, the nonstatic member a cannot be used as an
- initializer because a does not exist until an object of class X is constructed.
- You can use the static member b as an initializer because b is created
- independently of any objects of class X. You can declare the member b after its
- use as a default argument because the default values are not analyzed until
- after the final bracket } of the class declaration.
-
- class X
- {
- int a;
- f(int z = a) ; // error
- g(int z = b) ; // valid
- static int b;
- };
-
-
- ΓòÉΓòÉΓòÉ 8.8. Return Values ΓòÉΓòÉΓòÉ
-
- A value must be returned from a function unless the function has a return type
- of void. The return value is specified in a return statement. The following
- code fragment shows a function definition, including the return statement:
-
- int add(int i, int j)
- {
- return i + j; // return statement
- }
-
- The function add() can be called as shown in the following code fragment:
-
- int a = 10,
- b = 20;
- int answer = add(a, b); // answer is 30
-
- In this example, the return statement initializes a variable of the returned
- type. The variable answer is initialized with the int value 30. The type of the
- returned expression is checked against the returned type. All standard and
- user-defined conversions are performed as necessary.
-
- The following return statements show different ways of returning values to a
- caller:
-
- return; // Returns no value
- return result; // Returns the value of result
- return 1; // Returns the value 1
- return (x * x); // Returns the value of x * x
-
- Other than main(), if a function that does not have type void returns without a
- value (as in the first return statement shown in the example above) the &xcomp.
- &xcompos2. issues a warning message, and the result returned is undefined.
-
- Each time a function is called, new copies of its local variables are created.
- Because the storage for a local variable may be reused after the function has
- terminated, a pointer to a local variable or a reference to a local variable
- should not be returned.
-
- If a class object is returned, a temporary object may be created if the class
- has copy constructors or a destructor.
-
-
- ΓòÉΓòÉΓòÉ 8.8.1. Using References as Return Types ΓòÉΓòÉΓòÉ
-
- References can also be used as return types for functions. The reference
- returns the lvalue of the object to which it refers. This allows you to place
- function calls on the left side of assignment statements. Referenced return
- values are used when overloading assignment operators and overloading
- subscripting operators so that the results of the overloaded operators can be
- used as actual values.
-
-
- ΓòÉΓòÉΓòÉ 8.9. Pointers to Functions ΓòÉΓòÉΓòÉ
-
- A pointer to a function points to the address of the function's executable
- code. You can use pointers to call functions and to pass functions as arguments
- to other functions. You cannot perform pointer arithmetic on pointers to
- functions.
-
- The type of a pointer to a function is based on both the return type and
- argument types of the function.
-
- A declaration of a pointer to a function must have the pointer name in
- parentheses. Without them, the &xcomp. &xcompos2. would interpret the statement
- as a function that returns a pointer to a specified return type. For example:
-
- int *f(int a); // function f returning an int*
- int (*g)(int a); // pointer g to a function returning
- an int
-
- In the first declaration, f is interpreted as a function that takes an int as
- argument, and returns a pointer to an int. In the second declaration, g is
- interpreted as a pointer to a function that takes an int argument and that
- returns an int.
-
- For further details on pointers, see "Pointer Conversions" and "Pointers"
-
-
- ΓòÉΓòÉΓòÉ 8.10. Inline Functions ΓòÉΓòÉΓòÉ
-
- Inline functions are used to reduce the overhead of a normal function call. A
- function is declared inline by using the inline function specifier. The inline
- specifier is a suggestion to the &xcomp. that an inline expansion can be
- performed. Instead of transferring control to and from the function code
- segment, a modified copy of the function body may be substituted directly for
- the function call.
-
- An inline function can be declared and defined simultaneously. If it is
- declared with the keyword inline, it can be declared without a definition. The
- following code fragment shows an inline function definition. Note that the
- definition includes both the declaration and body of the inline function.
-
- inline int add(int i, int j) { return i + j; }
-
- Both member and nonmember functions can be inline. For a nonmember inline
- function, the function receives default internal linkage.
-
- The use of the inline specifier does not change the meaning of the function.
- The inline expansion of a function may not preserve the order of evaluation of
- the actual arguments. For more details, see "Compiler Options" in the
- Programming Guide.
-
- For further details on inlining, see "Inline Member Functions".
-
-
- ΓòÉΓòÉΓòÉ 8.11. Special C++ Functions ΓòÉΓòÉΓòÉ
-
- C++ supports several types of functions not found in ANSI C. These are briefly
- introduced below.
-
-
- ΓòÉΓòÉΓòÉ 8.11.1. Member Functions ΓòÉΓòÉΓòÉ
-
- Members functions are operators and functions that are declared within a class
- declaration. For a complete description, see "Member Functions"
-
-
- ΓòÉΓòÉΓòÉ 8.11.2. Overloaded Functions ΓòÉΓòÉΓòÉ
-
- Overloading functions allows you to define more than one function with the same
- name in the same scope. When the function is called, the &xcomp. &xcompos2.
- selects the correct function definition by comparing the actual arguments to
- the types of the formal arguments.
-
- For a complete description, see "Overloading Functions"
-
-
- ΓòÉΓòÉΓòÉ 8.11.3. Operator Functions ΓòÉΓòÉΓòÉ
-
- Overloading operators allows you to redefine most standard C++ operators when
- they are applied to class types. You can overload an operator by defining an
- operator function. An operator function must be either a class member function
- or must take at least one argument that is a class type or a reference to a
- class type. Operator functions are invoked implicitly, if they have been
- defined, to implement operators used with class types.
-
- For a complete description of operator functions, see "Overloading Operators"
-
-
- ΓòÉΓòÉΓòÉ 8.11.4. Constructor and Destructor Functions ΓòÉΓòÉΓòÉ
-
- A constructor is a class member function that has the same name as its class
- name. Constructors are used to initialize class objects. A destructor is a
- class member function that has the same name as its class and has a ~ (tilde)
- preceding the function name. Destructors are used to destroy class objects
- created with constructors. For a complete description, see "Constructors and
- Destructors"
-
-
- ΓòÉΓòÉΓòÉ 8.11.5. Conversion Functions ΓòÉΓòÉΓòÉ
-
- A conversion function is a member function that converts from its class type to
- another specified type. Conversion functions are useful for converting from
- class types to the standard types. For a complete description, see "Conversion
- Functions"
-
-
- ΓòÉΓòÉΓòÉ 8.11.6. Virtual Functions ΓòÉΓòÉΓòÉ
-
- A virtual function allows you to redefine a base class member function in a
- derived class. When thevirtual function is called for a derived class object,
- the derived class function is called and is said to override the base class
- function.
-
- You can only declare a virtualfunction when declaring nonstatic class member
- functions within a class declaration. For a complete description, see "Virtual
- Functions"
-
-
- ΓòÉΓòÉΓòÉ 8.11.7. Function Templates ΓòÉΓòÉΓòÉ
-
- A function template allows you to define a group of functions that are the same
- except for their return types, the types of one or more of their arguments, and
- the use of the types in the function body. When a function is called whose name
- matches the function template's name, a function can be generated with the
- appropriate return type or argument types.
-
- For a complete description, see "Function Templates"
-
-
- ΓòÉΓòÉΓòÉ 8.12. Related Information ΓòÉΓòÉΓòÉ
-
- "Declarations"
-
- "Member Functions"
-
- "Inline Member Functions"
-
- "C++ Overloading"
-
- "Special Member Functions"
-
- "Virtual Functions".
-
-
- ΓòÉΓòÉΓòÉ 9. Chapter 9. C++ Classes ΓòÉΓòÉΓòÉ
-
- This chapter introduces the concept of the class data type and discusses the
- following topics:
-
- o Introduction to C++ classes
- o Classes, structures, and unions
- o Class declarations and objects
- o Scope of class names.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 9.1. Introduction to C++ Classes ΓòÉΓòÉΓòÉ
-
- C++ provides a user-defined data type called a class.
-
- The C++ class is similar to the C structure data type. In C, a structure is
- composed of a set of data members. In C++, a class type is like a C structure
- except that a class is composed of a set of data members as well as an optional
- set of operations, that can be performed on the class.
-
- In C++, a class type can be declared with the keywords union, struct, or class.
- A union object can hold any one of a set of named members. Structure and class
- objects hold a complete set of members. Each class type represents a unique set
- of class members including data members, member functions, and other type
- names.
-
- Once you create a class type, you can declare one or more objects of that class
- type. For example,
-
- class X
- { /* define class members here */ };
- void main()
- {
- X xobject1; // create an object of class type X
- X xobject2; // create another object of class type X
- }
-
-
- ΓòÉΓòÉΓòÉ 9.1.1. Classes and Access Control ΓòÉΓòÉΓòÉ
-
- C++ facilitates data abstraction and encapsulation by providing access control
- for class types. For example, if you declare private data members and public
- member functions, a client program can only access the private members through
- the public member functions and friends of that class. Such a class would have
- data hiding because client programs do not have access to implementation
- details and are forced to use a public interface to manipulate objects of the
- class.
-
- You can control access to class members by using access specifiers In the
- following example, the classabc has three privatedata members a, b, and c, and
- three publicmember functions add(), mult(), and the constructor abc(). The
- main() function creates an object danforth of the abc class and then attempts
- to print the value of the member a for this object:
-
- #include <iostream.h>
- class abc
- {
- private:
- int a, b, c;
- public:
- abc(int p1, int p2, int p3): a(p1), b(p2), c(p3)
- {}
- int add() { return a + b + c ;}
- int mult() { return a * b * c; }
- };
- void main() {
- abc danforth(1,2,3);
- cout << "Here is the value of a " <<
- danforth.a << endl;
- // This causes an error because a is not
- // a public member and thus cannot be accessed
- // directly
- }
-
- Class members are private by default, so you could omit the keyword private in
- the definition of abc. Since a is not a public member, the attempt to access
- its value directly causes an error.
-
-
- ΓòÉΓòÉΓòÉ 9.1.2. Classes and Polymorphic Functions ΓòÉΓòÉΓòÉ
-
- Classes are also used in C++ to support polymorphic functions through
- overloaded functions (static compile time binding) and virtual functions (
- dynamic binding ). C++ allows you to redefine standard operators and functions
- through the concept of overloading. Operator overloading facilitates data
- abstraction by allowing you to use classes as easily as built-in types.
-
-
- ΓòÉΓòÉΓòÉ 9.1.3. Class Declaration Grammar ΓòÉΓòÉΓòÉ
-
- The syntax is:
-
- class-specifier:
- class-head
- {[member-list]
- }
-
- class-head:
- class-key
- class-key identifier
- [base-spec]
- class-key [identifier]
- base-spec
- class-key class-name
- [base-spec]
-
- class-key:
- class
- struct
- union
-
- A class-specifier is used to declare a class. Once a class-specifier has been
- seen and its members declared, a class is considered to be defined even if the
- member functions of that class are not yet defined.
-
- The member-list is optional. It specifies the class members, both data and
- functions, of the class class-name. If the member-list of a class is empty,
- objects of that class have a nonzero size. You can use a class-name within the
- member-list of the class specifier itself as long as the size of the class is
- not required. For further details, see "Class Member Lists"
-
- The base-spec is optional. It specifies the base class or classes from which
- the class class-name inherits members. If the base-spec is not empty, the class
- class-name is called a derived class .
-
- For a complete summary of class declaration grammar including member and base
- class grammar see "Class Declaration Grammar Summary" in Appendix B
-
-
- ΓòÉΓòÉΓòÉ 9.1.4. Class Declarator ΓòÉΓòÉΓòÉ
-
- The declarator for a class variable declared with the class, struct, or union
- keyword is an identifier. If the symbol * precedes the identifier, the
- identifier names a pointer to a class of the specified data type. If **
- precedes the identifier, the identifier names a pointer to a pointer to a class
- of the specified data type.
-
- If a constant expression enclosed in [ ] (brackets) follows the identifier, the
- identifier names an array of classes of the specified data type. If * precedes
- the identifier and a constant expression enclosed in [ ] follows the
- identifier, the identifier names an array of pointers to classes of the
- specified data type.
-
- You can use classes to build complicated declarators.
-
- The union type specifier can be used to declare a class declarator.
-
-
- ΓòÉΓòÉΓòÉ 9.1.5. Class Names ΓòÉΓòÉΓòÉ
-
- A class-name is a unique identifier that becomes a reserved word within its
- scope. The syntax is:
-
- class-name:
- identifier
-
- You can qualify the names of nested classes by using the :: (scope) operator
- and the name of their enclosing class. The syntax of a qualified-class-name is:
-
- qualified-class-name:
- class-name
- class-name ::
- qualified-class-name
-
- Where class-name::qualified-class-name specifies the name of the enclosing
- class (class-name) and the name of the nested class (qualified-class-name). For
- further details, see "Nested Classes"
-
- A complete-class-name is an alternative way of referring to a class after it
- has been declared. The syntax is:
-
- complete-class-name:
- qualified-class-name
- :: qualified-class-name
-
- An elaborated-type-specifier can also be used with a complete-class-name. The
- syntax is:
-
- :id='CPLRelabts2'.
- elaborated-type-specifier:
- class-key complete-class-name
- class-key identifier
- enum ::
- enum-name
- enum enum-name
-
- Enumerations are described in " "Enumerations" Enumerations "
-
- Once a class name is declared, that class name hides other declarations of the
- same name within the enclosing scope.
-
- If a class name is declared in the same scope as a function, enumerator, or
- object with the same name, that class can be referred to by using an
- elaborated-type-specifier. In the following example, the elaborated type
- specifier is used to refer to the class print that is hidden by the later
- definition of the function print().
-
- class print
- {
- /* definition of class print */
- };
- void print (class print*); // redefine print as a function
- // . // prefix class-name by class-key
- // . // to refer to class print
- // .
- void main ()
- {
- class print* paper; // prefix class-name
- by class-key
- // to refer to class print
- print(paper); // call function print
- }
-
- You can use an elaborated type specifier with a class name to declare a class.
- For more details on elaborated type specifiers, see "Incomplete Class
- Declarations"
-
- You can also qualify type names in order to refer to hidden type names in the
- current scope. You can use a qualified-type-name to reduce complex class name
- syntax by representing a qualified-class-name using a typedef. The syntax for a
- qualified-type-name is:
-
- qualified-type-name:
- typedef-name
- complete-class-name ::
- typedef-name
- :: typedef-name
-
- In the following example, a typedef is used so that the simple name nested can
- be used in place of outside::middle::inside .
-
- #include <iostream.h>
- class outside {
- public:
- class middle {
- public:
- class inside {
- private:
- int a;
- public:
- inside(int a_init = 0): a(a_init)
- {}
- void printa();
- };
- };
- };
- typedef outside::middle:
- :inside nested;
-
- void nested::printa() {
- cout << "Here is a " << this->a <<
- endl;
- }
- void main() {
- nested n(9);
- n.printa();
- }
-
- See "Nested Classes" for more details on nested classes.
-
-
- ΓòÉΓòÉΓòÉ 9.2. Classes, Structures, and Unions ΓòÉΓòÉΓòÉ
-
- In C++, a class type can be a union, structure, or class. Each is a type of the
- user-defined data type class. The default access depends on the class key:
-
- o The members of a class declared with the class key class are private by
- default. A class is inherited privately by default.
-
- o The members of a class declared with the class key struct are public by
- default. A structure is inherited publicly by default.
-
- o A union is a class declared with the class key union. The members of a union
- are publicby default and a union may not be used as a base class in
- derivation.
-
-
- ΓòÉΓòÉΓòÉ 9.2.1. Classes and Structures ΓòÉΓòÉΓòÉ
-
- The C++ class is an extension of the C structure. Because the only difference
- between a structure and a class is that a structure has publicaccess by default
- and a class has private access by default, you can use the keywords class or
- struct to define equivalent classes. For example, in the following code
- fragment, the class X is equivalent to the structure Y:
-
- class X
- {
- int a; // private by default
- public:
- int f() { return a = 5; }; // public member
- function
- };
- struct Y
- {
- int f() { return a = 5; }; // public by default
- private:
- int a; // private data member
- };
-
- If you define a structure and then declare an object of that structure using
- the keyword class, the members of the object are still public by default. In
- the following example, main() has access to the members of X even though X is
- declared as using the keyword class:
-
- #include <iostream.h>
- struct x {
- int a;
- int b;
- } ;
-
- class x X;
-
- void main() {
- X.a = 0;
- X.b = 1;
- cout << "Here are e and f " << X.a
- << " " << X.b << endl;
- }
-
-
- ΓòÉΓòÉΓòÉ 9.2.2. Aggregate Classes ΓòÉΓòÉΓòÉ
-
- An aggregate class is a class that has no constructors, no private or protected
- members, no base classes, and no virtual functions.
-
- For more details, see "Aggregate Initialization"
-
-
- ΓòÉΓòÉΓòÉ 9.2.3. Unions ΓòÉΓòÉΓòÉ
-
- A union is an object that can hold any one of a set of named members. The
- members can be of any data type. Members are overlaid in storage. The storage
- allocated for a union is equal to the storage required for the largest member
- of the union, plus any padding required for the union to end at a natural
- boundary of its strictest member. The strictest member is the one that must be
- aligned along the largest byte boundary.
-
- A union can have member functions, including constructors and destructors, but
- not virtual member functions. A union cannot be used as a base class and cannot
- be derived from a base class.
-
- A union member cannot be a class object that has a constructor, destructor or
- overloaded copy assignment operator. A member of a union cannot be declared
- with the keyword static . You can initialize only the first member of a union.
-
- The following example shows the initialization of the first union member
- birthday of the union variable people.
-
- union
- {
- char birthday[9];
- int age;
- float weight;
- } people = {"23/07/57"};
-
- You can also use constructors to initialize a union.
-
- The following example defines an unnamed union data type and a union variable
- named length, containing members of type long int, float, and double occupying
- the same storage.
-
- union
- {
- float metres;
- double centimetres;
- long inches;
- } length;
-
-
- ΓòÉΓòÉΓòÉ 9.2.4. Anonymous Unions ΓòÉΓòÉΓòÉ
-
- An anonymous union is a union without a class name. It cannot be followed by a
- declarator. An anonymous union is not a type; it cannot have member functions.
-
- The member names of an anonymous union must be distinct from other names within
- the scope in which the union is declared. You can use member names directly in
- the union scope without any additional member access syntax. For example, in
- the following code fragment, you can access the data members i and cptr
- directly because they are in the scope containing the anonymous union. Because
- i and cptr are union members and have the same address, you should only use one
- of them at a time. The assignment to the member cptr will change the value of
- the member i.
-
- void f()
- {
- union { int i; char* cptr ;};
- // .
- // .
- // .
- i = 5;
- cptr = "stringinunion"; // overrides i
- }
-
- An anonymous union cannot have protected or private members. Anonymous unions
- must be declared with the keyword static .
-
-
- ΓòÉΓòÉΓòÉ 9.3. Class Declarations and Objects ΓòÉΓòÉΓòÉ
-
- A class declaration creates a unique type class name. You can use a class type
- to create instances or objects of that class type. For example you can declare
- a class, structure, and union with class names X, Y, and Z respectively:
-
- class X { /* definition of class X /* };
- struct Y { /* definition of struct Y */ };
- union Z { /* definition of union Z */ };
-
- You can then declare objects of each of these class types. Remember that
- classes, structures, and unions are all types of C++ classes.
-
- void main()
- {
- X xobj; // declare a class object of class type
- X
- Y yobj; // declare a struct object of class type
- Y
- Z zobj; // declare a union object of class type
- Z
- }
-
- In C++, unlike C, you do not need to precede declarations of class objects with
- the keywords union, struct, and class unless the name of the class is hidden.
- For example,
-
- struct Y { /* ... */ };
- class X { /* ... */ };
- void main ()
- {
- int X; // hides the class name X
- Y yobj; // valid
- X xobj; // error, class name X is hidden
- class X xobj; // valid
- }
-
- For more details on hidden names, see "Scope of Class Names"
-
- When you declare more than one class object in a declaration, the declarators
- are treated as if declared individually. For example, if you declare two
- objects of class S in a single declaration:
-
- class S { /* ... */ };
- // .
- // .
- // .
- void main()
- {
- S S,T; // declare two objects of class type S
- }
-
- this declaration is equivalent to:
-
- class S { /* ... */ };
- void main()
- {
- S S;
- class S T; // keyword class is required
- // since variable S hides class type S
- }
-
- but is not equivalent to:
-
- class S { /* ... */ };
- // .
- // .
- // .
- void main()
- {
- S S;
- S T; // error, S class type is hidden
- }
-
- You can also declare references to classes, pointers to classes, and arrays of
- classes. For example,
-
- class X { /* ... */ };
- struct Y { /* ... */ };
- union Z { /* ... */ };
- void main()
- {
- X xobj;
- X &xref = xobj; // reference to class object
- of type X
- Y *yptr; // pointer to struct object of
- type Y
- Z zarray[10]; // array of 10 union objects of
- type Z
- }
-
- Objects of class types that are not copy restricted can be assigned, passed as
- arguments to functions, and returned by functions.
-
- For more details on objects, see also "Objects" Initialization of classes is
- discussed in "Initialization by Constructor"
-
-
- ΓòÉΓòÉΓòÉ 9.4. Scope of Class Names ΓòÉΓòÉΓòÉ
-
- A class declaration introduces the class name into the scope where it is
- declared. Any class, object, function or other declaration of that name in an
- enclosing scope is hidden. If a class name is declared in a scope where an
- object, function, or enumerator of the same name is also declared, you can only
- refer to the class by using the elaborated type specifier. The class key
- (class, struct, or union) must precede the class name to identify it. For
- example:
-
- class x { int a; }; // declare a class
- typeclass-name
- x
- x xobject; // declare object of class type x
- int x(class x*) // redefine x to be a function
- {return 0;} // use class-key class to define
- // a pointer to the class type x
- // as the function argument
- void main()
- {
- class x* xptr; // use class-key classto
- define
- // a pointer to class type x
- xptr = &xobject; // assign pointer
- x(xptr); // call function x with pointer
- to class x
- }
-
- An elaborated type specifier can be used in the declaration of objects and
- functions. See "Class Names" for an example.
-
- An elaborated type specifier can also be used in the incomplete declaration of
- a class type to reserve the name for a class type within the current scope.
-
-
- ΓòÉΓòÉΓòÉ 9.4.1. Incomplete Class Declarations ΓòÉΓòÉΓòÉ
-
- An incomplete class declaration is a class declaration that does not define any
- class members. You cannot declare any objects of the class type or refer to the
- members of a class until the declaration is complete. However, an incomplete
- declaration allows you to make specific references to a class prior to its
- definition as long as the size of the class is not required. For example, you
- can define a pointer to the structure first in the definition of the
- structuresecond. first is declared in an incomplete class declaration prior to
- the definition of second, and the definition of oneptr in structure second does
- not require the size of first:
-
- struct first; // incomplete declaration of struct
- first
- struct second // complete declaration of struct
- second
- {
- first* oneptr; // pointer to structfirst
- refers to
- // struct first prior to its complete
- // declaration
- first one; // error, you cannot declare an
- object of
- // an incompletely declared class type
- int x, y;
- };
-
- struct first // complete declaration of struct
- first
- {
- second two; // define an object of class
- type second
- int z;
- };
-
- If you declare a class with an empty member list, it is a complete class
- declaration. For example,
-
- class X; // incomplete class declaration
- class Z {}; // empty member list
- class Y
- {
- public:
- X yobj; // error, cannot create an object of an
- // incomplete class type
- Z zobj; // valid
- };
-
- Member lists are described on page Class Member Lists.
-
-
- ΓòÉΓòÉΓòÉ 9.4.2. Nested Classes ΓòÉΓòÉΓòÉ
-
- A nested class is declared within the scope of another class. The name of a
- nested class is local to its enclosing class. Unless you use explicit pointers,
- references, or object names, declarations in a nested class can only use
- visible constructs, including type names, static members, and enumerators from
- the enclosing class and global variables.
-
- Member functions of a nested class follow regular access rules and have no
- special access privileges to members of their enclosing classes. Member
- functions of the enclosing class have no special access to members of a nested
- class.
-
- You can define member functions and static data members of a nested class in
- the global scope. For example, in the following code fragment, you can access
- the static members x and y and member functions f() and g() of the nested class
- nested by using a qualified type name. Qualified type names allow you to define
- a typedef to represent a qualified class name. You can then use the typedef
- with the :: (scope) operator to refer to a nested class or class member, as
- shown in the following example:
-
- class outside
- {
- public:
- class nested
- {
- public:
- static int x;
- static int y;
- int f();
- int g();
- };
- };
- int outside::nested::x = 5;
- int outside::nested::f() { return 0;};
- typedef outside::nested outnest; // define a typedef
- int outnest::y = 10; // use typedef with ::
- int outnest::g() { return 0;};
- // . . .
-
- Qualified class names are described on page -- Reference CPLRclaQualClas not
- found --.
-
-
- ΓòÉΓòÉΓòÉ 9.4.3. Local Classes ΓòÉΓòÉΓòÉ
-
- A local class is declared within a function definition. The local class is in
- the scope of the enclosing function scope. Declarations in a local class can
- only use type names, enumerations, static variables from the enclosing scope,
- as well as external variables and functions. For example:
-
- int x; // global variable
- void f() // function definition
- {
- static int y; // static variable y can
- be used by
- // local class
- int x; // auto variable x cannot
- be used by
- // local class
- extern int g(); // extern function g can
- be used by
- // local class
- class local // local class
- {
- int g() { return x;} // error, local
- variable
- x
- // cannot be used by g
- int h() { return y;} // valid,static
- variable
- y
- int k() { return ::x;} // valid, global x
- int l() { return g();} // valid, extern
- function g
- };
- }
- void main()
- {
- local* z; // error, local is undefined
- // .
- // .
- // .
- }
-
- Member functions of a local class have to be defined within their class
- definition. Thus, member functions of a local class must be inline functions.
- Like all member functions, those defined within the scope of a local class do
- not need the keyword inline.
-
- A local class cannot have static data members. In the following example, an
- attempt to define a static member of a local class causes an error.
-
- void f()
- {
- class local
- {
- int f(); // error, local class has noninline
- // member function
- int g() {return 0;} // valid, inline
- member
- function
- static int a; // error, static is not allowed
- for
- // local class
- int b; // valid, nonstatic variable
- };
- }
- // . . .
-
- An enclosing function has no special access to members of the local class.
-
-
- ΓòÉΓòÉΓòÉ 9.4.4. Local Type Names ΓòÉΓòÉΓòÉ
-
- Local type names follow the same scope rules as other names. Type names defined
- within a class declaration have local scope and cannot be used outside their
- class without qualification.
-
- If you use a class name, typedef name, or a constant name that is used in a
- type name, in a class declaration, you cannot redefine that name after it is
- used in the class declaration. For example:
-
- void main ()
- {
- typedef double db;
- struct st
- {
- db x;
- typedef int db; // error
- db y;
- };
- }
-
- The following declarations are valid:
-
- typedef float T;
- class s {
- typedef int T;
- void f(const T);
- };
-
- Here, function f() takes an argument of type s::T. However, the following
- declarations, where the order of the members of s has been reversed, cause an
- error:
-
- typedef float T;
- class s {
- void f(const T);
- typedef int T;
- };
-
- In a class declaration, you cannot redefine a name that is not a class name or
- a typedef name to a class name or typedef name once you have used that name in
- the class declaration.
-
-
- ΓòÉΓòÉΓòÉ 9.5. Related Information ΓòÉΓòÉΓòÉ
-
- "The C++ Language"
-
- "C++ Support of Object-Oriented Programming"
-
- "Class Members and Friends "
-
- "Inheritance"
-
-
- ΓòÉΓòÉΓòÉ 10. Chapter 10. Class Members and Friends ΓòÉΓòÉΓòÉ
-
- This chapter describes class members and friends, including the following
- topics:
-
- o Class member lists
- o Data members
- o Class type class members
- o Member bit fields
- o Member functions
- o Member scope
- o Pointers to members
- o The this pointer
- o Static members
- o Member access
- o Friends.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 10.1. Class Member Lists ΓòÉΓòÉΓòÉ
-
- An optional member list declares objects called class members. Class members
- can be data, functions, classes, enumeration, bit fields, and type names. A
- member list is the only place you can declare class members. Friend
- declarations are not class members but must appear in member lists.
-
- You can access members by using the class access . (dot) and -> (arrow)
- operators.
-
-
- ΓòÉΓòÉΓòÉ 10.1.1. Member List Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for a member list is:
-
- member-list:
- member-declaration
- [member-list]
- access-specifier
- :[member-list]
-
- member-declaration:
- [decl-specifiers][member-declarator-list]
- ;
- function-definition [;]
- qualified-name ;
-
- member-declarator-list:
- member-declarator
- member-declarator-list ,
- member-declarator
-
- member-declarator:
- declarator
- [pure-specifier]
- [identifier]
- :
- constant-expression
-
- :id='Atz3230antl'.
- pure-specifier:
- = 0
-
- A member-declaration declares a class member for the class containing the
- declaration.
-
- An access-specifier is one of public, private, or protected.
-
- decl-specifiers are described in "Specifiers" They include the following:
-
- o storage-class-specifiers
- o type-specifiers
- o fct-specifiers
- o template-specifier
- o friend
- o typedef.
-
- A member-declaration that is a qualified-name followed by a ; (semi colon) is
- used to restore access to members of base classes and is described in "Access
- Declarations".
-
- A member-declarator declares an object, function, or type within a declaration.
- It cannot contain an initializer. You can initialize a member by using a
- constructor or, if the member belongs to an aggregate class, by using a brace
- initializer list ( a list surrounded by braces { }) in the declarator list. You
- must explicitly initialize a class containing constant or reference members
- with a brace initializer list or explicitly with a constructor. Initialization
- using an brace initializer list is described in "Aggregate Initialization".
- Explicit initialization with a constructor is described in "Explicit
- Initialization".
-
- A member declarator of the form:
-
- [ identifier ] :
- constant-expression
-
- specifies a bit field.
-
- A pure-specifier indicates that a function has no definition. A pure-specifier
- is only used with virtual member functions. A pure-specifier replaces the
- function definition of a member function in the member list. pure-specifiers
- are described in "Virtual Functions"
-
- You can use the storage-class specifier static (but not extern, auto or
- register), in amember list. For more details, see "Static Members"
-
- The order of mapping of class members in a member list is implementation
- dependent. For more details, see "Classes, Structures, and Unions" in "Appendix
- C.
-
- For a complete summary of class declaration grammar including class member and
- base class grammar, see "Class Declaration Grammar Summary" in Appendix B
-
-
- ΓòÉΓòÉΓòÉ 10.2. Data Members ΓòÉΓòÉΓòÉ
-
- Data members include members that are declared with any of the fundamental
- types, as well as other types, including pointer, reference, array types, and
- user-defined types. You can declare a data member the same way as a variable,
- except that explicit initializers are not allowed inside the class definition.
-
- If an array is declared as a nonstatic class member, you must specify all of
- the dimensions of the array.
-
-
- ΓòÉΓòÉΓòÉ 10.3. Class Type Class Members ΓòÉΓòÉΓòÉ
-
- A class can have members that are of a class type or are pointers or references
- to a class type. Members that are of a class type must be of a class type that
- is previously declared. An incomplete class type can be used in a member
- declaration as long as the size of the class is not needed. For example, a
- member can be declared that is a pointer to an incomplete class type. A class X
- cannot have a member that is of type X, but it can contain pointers to X,
- references to X, and static objects of X. Member functions of X can take
- arguments of type X and have a return type of X. For example:
-
- class X
- {
- X();
- X *xptr;
- X &xref;
- static X xcount;
- X xfunc(X);
- };
-
- The bodies of member functions are always processed after the definition of
- their class is complete. Thus, the body of a member function can use the
- enclosing class. Consider the following example:
-
- class Y
- {
- public:
- int a;
- Y ();
- private:
- int f() {return sizeof(Y);}
- void g(Y yobj);
- Y h(int a);
- };
-
- In this example, the inline function f() uses the size of class Y.
-
-
- ΓòÉΓòÉΓòÉ 10.4. Member Bit Fields ΓòÉΓòÉΓòÉ
-
- A class can contain packed data known as bit fields. You can use bit fields for
- data that requires just a few bits of storage. The syntax for a bit field is:
-
- [ identifier ] :
- constant-expression
-
- The constant expression specifies how many bits the field reserves. A bit field
- that is defined as having a length of 0 (zero) causes the next field to be
- aligned on the next integer boundary. Bit fields with a length of zero must be
- unnamed.
-
- Unlike ANSI C, bit fields can be any integral type or enumeration type. When
- you assign a value to a bit field that is out of range, the bit pattern is
- preserved and the appropriate bits are assigned.
-
- The following restrictions apply to member bit fields. You cannot:
-
- o Have a reference to a bit field
- o Define an array of bit fields
- o Take the address of a bit field.
-
- The maximum bit field length is implementation dependent. For more details see
- "Bit Fields" in Appendix C.
-
-
- ΓòÉΓòÉΓòÉ 10.5. Member Functions ΓòÉΓòÉΓòÉ
-
- Member functions are operators and functions that are declared as members of a
- class. Member functions do not include operators and functions declared with
- the friend specifier. These are called friends of a class.
-
- The definition of a member function is within the scope of its enclosing class.
- The body of a member function is analyzed after the class declaration so that
- members of that class can be used in the member function body. When the
- functionadd() is called in the following example, the data variables a, b, and
- c may be used in the body of add().
-
- class x
- {
- public:
- int add() // inline member function add
- {return a+b+c;};
- private:
- int a,b,c;
- };
-
- For information on static member functions, see "Static Member Functions" For
- more general information on functions, see Chapter 8, "Functions" For more
- general information on functions, see Chapter 8, "Functions"
-
-
- ΓòÉΓòÉΓòÉ 10.5.1. const and volatile Member Functions ΓòÉΓòÉΓòÉ
-
- A member function declared with the const qualifier can be called for constant
- and nonconstant objects. A nonconstant member function can only be called for a
- nonconstant object. Similarly, a member function declared with the volatile
- qualifier can be called for volatile and nonvolatile objects. A nonvolatile
- member function can only be called for a nonvolatile object.
-
-
- ΓòÉΓòÉΓòÉ 10.5.2. Virtual Member Functions ΓòÉΓòÉΓòÉ
-
- Virtual member functions are declared with the keyword virtual.They allow
- dynamic binding of member functions. Because all virtual functions must be
- member functions, virtual member functions are simply called virtual functions.
-
- If the definition of a virtual function is replaced by a pure specifier in the
- declaration of the function, the function is said to be declared pure. A class
- that has at least one pure virtual function is called an abstract class.
-
-
- ΓòÉΓòÉΓòÉ 10.5.3. Special Member Functions ΓòÉΓòÉΓòÉ
-
- Special member functions are used to create, destroy, initialize, convert, and
- copy class objects. These include constructors, destructors, conversion
- constructors, conversion functions, and copy constructors.
-
-
- ΓòÉΓòÉΓòÉ 10.5.4. Inline Member Functions ΓòÉΓòÉΓòÉ
-
- A member function that is both declared and defined in the class member list is
- called an inline member function. Member functions containing a few lines of
- code are usually declared inline.
-
- An equivalent way to declare an inline member function is to declare it outside
- of the class declaration using the keyword inline and the :: (scope) operator
- to identify the class the member function belongs to. For example:
-
- class Y
- {
- char* a;
- public:
- char* f() {return a;}
- };
-
- is equivalent to:
-
- class Z
- {
- char* a;
- public:
- char* f();
- };
- // .
- // .
- // .
- inline char* Z::f() {return a;}
-
- When you declare an inline function without the inline keyword and do not
- define it in the class member list, you cannot call the function before you
- define it. Thus, in the above example you could not call f() until after its
- definition.
-
- Inline member functions have internal linkage. Noninline member functions have
- external linkage.
-
- For more details, see "Inline Functions"
-
-
- ΓòÉΓòÉΓòÉ 10.5.5. Member Function Templates ΓòÉΓòÉΓòÉ
-
- Member function templates are described in "Member Function Templates"
-
-
- ΓòÉΓòÉΓòÉ 10.6. Member Scope ΓòÉΓòÉΓòÉ
-
- Member functions and static members can be defined outside their class
- declaration if they have already been declared, but not defined, in the class
- member list. Nonstatic data members are defined when their class is
- instantiated. The declaration of a static data member is not a definition. The
- declaration of a member function is a definition if the body of the function is
- also given.
-
- Whenever the definition of a class member appears outside of the class
- declaration, the member name must be qualified by the class name using the ::
- (scope) operator. For example:
-
- #include <iostream.h>
- class X
- {
- public:
- int a, b ; // public data members
- int add(); // member function declaration only
- };
- int a = 10 ; // global variable
- // define member function outside its class declaration
- int X::add() {return a + b;};
- // .
- // .
- // .
- void main()
- {
- int answer;
- X xobject;
- xobject.a = 1;
- xobject.b = 2;
- answer = xobject.add();
- cout << xobject.a << " + " <<
- xobject.b << " = " << answer;
- }
-
- The output for this example is: 1 + 2 = 3
-
- All member functions are in class scope even if they are defined outside their
- class declaration. In the above example, the member function add() returns the
- data member a, not the global variable a.
-
- The name of a class member is local to its class. Unless you use one of the
- class access operators, . (dot) or -> (arrow), or the :: (scope) operator, you
- can only use a class member in a member function of its class and in nested
- classes. You can only use types, enumerations and static members in a nested
- class without qualification with the :: (scope) operator.
-
- The order of search for a name in a member function body is:
-
- o Within the member function body itself
- o Within the all the enclosing classes, including inherited members of those
- classes.
- o Within the lexical scope of the body declaration.
-
- The search of the enclosing classes, including inherited members, is
- demonstrated in the following example:
-
- class A { /* */ };
- class B { /* */ };
- class C { /* */ };
- class Z : A {
- class Y : B {
- class X : C { int f(); /* ... */ };
- };
- };
- int Z:::X f()
- {
- /*
- ...
- */
- j();
- /*
- ...
- */
- }
-
- In this example, the search for the name j in the definition of the function f
- follows this order:
-
- o In the body of the function f
-
- o In X and in its base class C
-
- o In Y and in its base class B
-
- o In Z and in its base class A
-
- o In the lexical scope of the body of f. In this case, this is global scope.
-
- Note: When the containing classes are being searched, only the definitions of
- the containing classes and their base classes are searched. The scope
- containing the base class definitions (global scope, in this example) is not
- searched.
-
-
- ΓòÉΓòÉΓòÉ 10.7. Pointers to Members ΓòÉΓòÉΓòÉ
-
- Pointers to members allow you to refer to nonstatic members of class objects.
- You cannot use a pointer to member to point to a static class member because
- the address of a static member is not associated with any particular object. To
- point to a static class member, you must use a normal pointer.
-
- You can use pointers to member functions in the same manner as pointers to
- functions. You can compare pointers to member functions, assign values to them,
- and use them to call member functions. Note that a member function does not
- have the same type as a nonmember function that has the same number and type of
- arguments and the same return type.
-
- Pointers to members can be declared and used as shown in the following example,
-
- #include <iostream.h>
- class X
- {
- public:
- int a;
- void f(int b) {cout << "The value of b is
- "<< b << endl;}
- };
- // .
- // .
- // .
- void main ()
- {
- // declare pointer to data member
- int X::*ptiptr = &X::a;
- // declare a pointer to member function
- void (X::* ptfptr) (int) = &X::f;
- X xobject; // create an object of class
- type X
- xobject.*ptiptr = 10; // initialize data member
- cout << "The value of a is " << xobject.*ptiptr
- << endl;
- (xobject.*ptfptr) (20); // call member function
- }
-
- The output for this example is:
-
- The value of a is 10
- The value of b is 20
-
- In order to reduce complex syntax, you can declare a typedef to be a pointer
- to a member. A pointer to a member can be declared and used as shown in the
- following code fragment:
-
- typedef void (X::*ptfptr) (int); // declare typedef
- void main ()
- {
- // .
- // .
- // .
- ptfptr ptf = &X::f; // use typedef
- X xobject;
- (xobject.*ptf) (20); // call function
- }
-
- The pointer to member operators.* and ->* are used to bind a pointer to a
- member of a specific class object. Because the precedence of ( ) (function call
- operator) is higher than .* and ->*, you must use parentheses to call the
- function pointed to by ptf.
-
- For more details, see "Pointer to Member Operators"
-
-
- ΓòÉΓòÉΓòÉ 10.8. The this Pointer ΓòÉΓòÉΓòÉ
-
- The keyword this identifies a special type of pointer. When a nonstatic member
- function is called, the this pointer identifies the class object which the
- member function is operating on. You cannot declare the this pointer or make
- assignments to it.
-
- The type of the this pointer for a member function of a class type X, is X*
- const. If the member function is declared with the constant qualifier, the type
- of the this pointer for that member function for class X, is const X* const. If
- the member function is declared with the volatile qualifier, the type of the
- this pointer for that member function for class X is volatile X* const.
-
- this is passed as a hidden argument to all nonstatic member function calls and
- is available as a local variable within the body of all nonstatic functions.
-
- For example, you can refer to the particular class object that a member
- function is called for by using the this pointer in the body of the member
- function.The following code example produces the output a = 5:
-
- #include <iostream.h>
- class X
- {
- int a;
- public:
- // The 'this' pointer is used to retrieve 'xobj.a'
- hidden by
- // the automatic variable 'a'
- void Set_a(int a) { this->a = a; }
- void Print_a() { cout << "a = " <<
- a << endl; }
- };
- void main()
- {
- X xobj;
- int a = 5;
- xobj.Set_a(a);
- xobj.Print_a();
- }
-
- Unless a class member name is hidden, using the class member name is equivalent
- to using the class member name qualified with the this pointer.
-
- The following example shows code using class members without the this pointer.
- The comments on each line show the equivalent code with the hidden use of the
- this pointer.
-
- #include <string.h>
- #include <iostream.h>
- class X
- {
- int len;
- char *ptr;
- public:
- int GetLen() // int GetLen (X* const this)
- { return len; } // { return this->len;
- }
- char * GetPtr() // char * GetPtr (X* const this)
- { return ptr; } // { return this->ptr;
- }
- X& Set(char *);
- X& Cat(char *);
- X& Copy(X&);
- void Print();
- };
- X& X::Set(char *pc) // X& X::Set(X* const this,
- char *pc)
- {
- len = strlen(pc); // this->len = strlen(pc);
- ptr = new char[len]; // this->ptr = new
- char[this->len];
- strcpy(ptr, pc); // strcpy(this->ptr, pc);
- return *this;
- }
- X& X::Cat(char *pc) // X& X::Cat(X* const this,
- char *pc)
- {
- len += strlen(pc); // this->len += strlen(pc);
- strcat(ptr,pc); // strcat(this->ptr,pc);
- return *this;
- }
- X& X::Copy(X& x) // X& X::Copy(X* const this,
- X& x)
- {
- Set(x.GetPtr()); // this->Set(x.GetPtr(&x));
- return *this;
- }
- void X::Print() // void X::Print(X* const
- this)
- {
- cout << ptr << endl; // cout <<
- this->ptr << endl;
- }
- void main()
- {
- X xobj1;
- xobj1.Set("abcd").Cat("efgh");
- // xobj1.Set(&xobj1, "abcd").Cat(&xobj1, "efgh");
- xobj1.Print(); // xobj1.Print(&xobj1);
- X xobj2;
- xobj2.Copy(xobj1).Cat("ijkl");
- // xobj2.Copy(&xobj2, xobj1).Cat(&xobj2, "ijkl");
- xobj2.Print(); // xobj2.Print(&xobj2);
- }
-
- The above example produces the following output:
-
- abcdefgh
- abcdefghijkl
-
-
- ΓòÉΓòÉΓòÉ 10.9. Static Members ΓòÉΓòÉΓòÉ
-
- Class members can be declared using the storage-class specifier static in the
- class member list. There is only one copy of the static member that is shared
- by all objects of a class in a program. When you declare an object of a class
- having a static member, the static member is not part of the class object.
-
- A typical use of static members is for recording data common to all objects of
- a class. For example, you can use a static data member as a counter to store
- the number of objects of a particular class type that are created. Each time a
- new object is created, this static data member can be incremented to keep track
- of the total number of objects.
-
- The declaration of a static member in the member list of a class is not a
- definition. The definition of a static member is equivalent to an external
- variable definition. You must define the static member outside of the class
- declaration. For example:
-
- class X
- {
- public:
- static int i;
- }
- int X:
- :i = 0; // definition outside class declaration
- // .
- // .
- // .
-
- A static member can be accessed from outside of its class only if it is
- declared with the keyword public . You can then access the static member by
- qualifying the class name using the :: (scope) operator. In the following
- example:
-
- class X
- {
- public:
- static int f();
- };
- // .
- // .
- // .
- void main ()
- {
- X::f();
- }
-
- you can refer to the static member f() of class type X as X:.
-
-
- ΓòÉΓòÉΓòÉ 10.9.1. Using the Class Access Operators with Static Members ΓòÉΓòÉΓòÉ
-
- You can also access a static member from a class object by using the class
- access operators . ( dot ) and -> ( arrow ). For example:
-
- #include <iostream.h>
- class X
- {
- static int cnt;
- public:
- // The following routines all set X's static variable
- cnt
- // and print its value
- void Set_Show (int i)
- { X::cnt = i;
- cout << "X::cnt = " << X::cnt
- << endl; }
- void Set_Show (int i, int j )
- { this->cnt = i+j;
- cout << "X::cnt = " << X::cnt
- << endl; }
- void Set_Show (X& x, int i)
- { x.cnt = i;
- cout << "X::cnt = " << X::cnt
- << endl; }
- };
- int X::cnt;
- void main()
- {
- X xobj1, xobj2;
- xobj1.Set_Show(11);
- xobj1.Set_Show(11,22);
- xobj1.Set_Show(xobj2, 44);
- }
-
- The above example produces the following output:
-
- X::cnt = 11
- X::cnt = 33
- X::cnt = 44
-
- When a static member is accessed through a class access operator, the
- expression on the left of the . or -> operator is not evaluated.
-
- A static member can be referred to independently of any association with a
- class object because there is only one static member shared by all objects of a
- class. A static member can exist even if no objects of its class have been
- declared.
-
- When you access a static member, the expression that you use to access the
- static member is not evaluated. In the following example, the external function
- f() returns class type X. The function f() can be used to access the static
- member i of class X. The function f() itself is not called.
-
- class X
- {
- public:
- static int i;
- };
- int X:
- :i = 10;
- X f() { /* ... */ }
- void main ()
- {
- int a;
- a = f().i; // f().i does not call f()
- }
-
-
- ΓòÉΓòÉΓòÉ 10.9.2. Static Data Members ΓòÉΓòÉΓòÉ
-
- Static data members of global classes have external linkage and can be
- initialized in file scope like other global objects. Static data members follow
- the usual class access rules except that they can be initialized in file scope.
- Thus, static data members and their initializers can access other static
- private and protected members of their class. The initializer for a static data
- member is in the scope of the class declaring the member.
-
- You can only have one definition of a static member in a program. If a static
- data member is not initialized, it is assigned a zero default value.
-
- Local classes cannot have static data members.
-
- The following example shows the declaration, initialization, use, and scope of
- the static data member si and static member functions Set_si(int) and
- Print_si().
-
- #include <iostream.h>
- class X
- {
- int i;
- static int si;
- public:
- void Set_i(int i) { this->i = i; }
- void Print_i() { cout << "i = " <<
- i << endl; }
- // Equivalent to:
- // void Print_i(X* this)
- // { cout << "X:
- :i = " << this->i
- << endl; }
- static void Set_si(int si) { X::si = si; }
-
- static void Print_si()
- { cout << "X::si = " << X::si <<
- endl; }
- // Print_si doesn't have a 'this' pointer
- };
- int X::si = 77; // Initialize static data member
- void main()
- {
- X xobj;
- // Non-static data members and functions belong to
- specific
- // instances (here xobj) of class X
- xobj.Set_i(11);
- xobj.Print_i();
-
- // static data members and functions belong to the
- class and
- // can be accessed without using an instance of class
- X
- X::Print_si();
- X::Set_si(22);
- X::Print_si();
- }
-
- The above example produces the following output:
-
- i = 11
- X::si = 77
- X::si = 22
-
-
- ΓòÉΓòÉΓòÉ 10.9.3. Static Member Functions ΓòÉΓòÉΓòÉ
-
- You cannot have static and nonstatic member functions with the same names and
- the same number and type of arguments.
-
- A static member function does not have a this pointer. You can call a static
- member function using the this pointer of a nonstatic member function. In the
- following example, the nonstatic member function printall() calls the static
- member function f() using the this pointer:
-
- #include <iostream.h>
- class c {
- static void f() { cout << "Here is i
- " << i << endl;}
- static int i;
- int j;
- public:
- c(int firstj): j(firstj) {}
- void printall();
- };
- void c::printall() {
- cout << "Here is j " << this->j <<
- endl;
- this->f();
- }
- int c:
- :i = 3;
- void main() {
- class c C(0);
- C.printall();
- }
-
- A static member function cannot be declared with the keyword virtual.
-
- A static member function can access only the names of static members,
- enumerators, and nested types of the class in which it is declared.
-
-
- ΓòÉΓòÉΓòÉ 10.10. Member Access ΓòÉΓòÉΓòÉ
-
- Member access determines if a class member is accessible in an expression or
- declaration. Note that accessibility and visibility are independent. Visibility
- is based on the scoping rules of C++. A class member can be visible and
- inaccessible at the same time. This section describes how you control the
- access to the individual nonderived class members by using access specifiers
- when you declare class members in a member list.
-
- The default access for an individual class member depends on the class key used
- in the class declaration. Members of classes declared with the keyword class
- are private by default. Members of classes declared with the keyword struct or
- union are public by default.
-
- The access specifier protected is meaningful only in the context of derivation.
- You can control the access to inherited members (that is, base class members)
- by including access specifiers in the base list of the derived class
- declaration.You can also restore the access to an inherited member from a
- derived class by using an access declaration.
-
- Access for inherited members is described in "Inherited Member Access"
- including: "Protected Members", "Derivation Access and Base Classes", "Access
- Declarations", and "Access Resolution"
-
-
- ΓòÉΓòÉΓòÉ 10.10.1. Access Specifiers ΓòÉΓòÉΓòÉ
-
- The syntax for an access-specifier is:
-
- access-specifier:
- public
- private
- protected
-
- Member lists can include access specifiers as a labels. Members declared after
- these labels have access as specified by the label they follow. An access
- specifier determines the access for members until another access specifier is
- used or until the end of the class declaration. You can use any number of
- access specifiers in any order. For example:
-
- class X
- {
- int a; // private data by default
- public:
- void f(int); // public function
- int b; // public data
- private:
- int c; // private data
- protected:
- void g(int); // protected function
- };
- struct Y
- {
- int a; // public data by default
- public:
- int b; // public data
- private:
- void g(int); // private function
- int c; // private data
- };
-
- The three access specifiers have the following effect:
-
- o public class members can be accessed by any function, file or class.
-
- o private class members can be accessed only by member functions and friends of
- the class in which the member is declared.
-
- o protected class members can be accessed only by member functions and friends
- of the class in which they are declared and by member functions and friends
- of classes derived from the class in which the protected members are
- declared. The access specifier protected can be used for nonbase class
- members, but it is equivalent to private unless it is used in a base class
- member declaration or in a base list. For more details, see "Protected
- Members".
-
-
- ΓòÉΓòÉΓòÉ 10.11. Friends ΓòÉΓòÉΓòÉ
-
- A friend of a class X is a function or class that is granted the same access to
- X as the members of X. Functions declared with the friend specifier in a class
- member list are called friend functions of that class. Classes declared with
- the friend specifier in the member list of another class are called friend
- classes of that class. Friend functions and classes do not automatically become
- members of the class they are declared in.
-
- A class Y must be defined before any member of Y can be declared a friend of
- another class.
-
- In the following example, the friend function print is a member of class Y and
- accesses the private data members a and b of class X.
-
- #include <iostream.h>
- class X;
- class Y
- {
- public:
- void print(X& x);
- };
- class X
- {
- public:
- X() {a=1; b=2;}
- private:
- int a, b;
- friend void Y::print(X& x);
- };
- void Y::print(X& x)
- {
- cout << "A is "<< x.a << endl;
- cout << "B is " << x.b <<
- endl;
- }
- void main ()
- {
- X xobj;
- Y yobj;
- yobj.print(xobj);
- }
-
- You can declare an entire class as a friend. In the following example, the
- friendclass F has a member function print that accesses the private data
- members a and b of class X and performs the same task as the friend function
- print in the above example. Any other members declared in class F also have
- access to all members of class X. In the following example, the friend class F
- has not been previously declared, so an elaborated type specifier and a
- qualified type specifier are used to specify the class name.
-
- #include <iostream.h>
- class X
- {
- public:
-
- X() {a=1; b=2;} // constructor
- private:
- int a, b;
- friend class F; // friend class
- };
- class F
- {
- public:
- void print(X& x)
- {
- cout << "A is " << x.a <<
- endl;
- cout << "B is " << x.b <<
- endl;
- }
- // .
- // .
- // .
- };
- void main ()
- {
- X xobj;
- F fobj;
- fobj.print(xobj);
- }
-
- Both the above examples produce the output:
-
- A is 1
- B is 2
-
- If the friend class has been previously declared, you can omit the keyword
- class, as shown in the following example:
-
- class F;
- class X
- {
- public:
-
- X() {a=1; b=2;}
- private:
- int a, b;
- friend F; // elaborated-type-specifier not required
- };
- // .
- // .
- // .
-
- Elaborated type specifiers are described on page -- Reference CPLRelabts not
- found --.
-
-
- ΓòÉΓòÉΓòÉ 10.11.1. Friend Scope ΓòÉΓòÉΓòÉ
-
- The name of a friend function or class first introduced in a friend declaration
- is not in the scope of the class granting friendship (also called the enclosing
- class) and is not a member of the class granting friendship.
-
- The name of a function first introduced in a friend declaration is in the scope
- of the first nonclass scope that contains the enclosing class. The body of a
- function provided in a friend declaration is handled in the same way as a
- member function defined within a class. Thus, processing of the definition
- does not start until the end of the outermost enclosing class. In addition,
- unqualified names in the body of the function definition are searched for
- starting from the class containing the function definition.
-
- A class that is first declared in a friend declaration has the same scope as
- the class granting friendship. For example:
-
- class B {};
- class A
- {
- friend class B; // global class B is a friend of A
- };
-
- If the name of a friend class has been introduced before the friend
- declaration, the &xcomp. &xcompos2. searches for a class name that matches the
- name of the friend class beginning at the scope of the friend declaration. If
- the declaration of a nested class is followed by the declaration of a friend
- class with the same name, the nested class is a friend of the enclosing class.
- For example:
-
- class B { void f(); };
- class C { void f(); };
- class A {
- class B;
- friend class B; // A::B is a friend of A
- friend class C; // global class C is a friend
- of A
- class B {
- void f() { A::a = 0;}
- };
- class C {
- void f() { A::a = 0;} // error, A is
- private
- };
- };
-
- A friend class that is declared in a nested class has the scope of it enclosing
- class. For example:
-
- class C
- {
- class B { /* ... */ };
- class A
- {
- friend class B; // friend is C::B
- };
- };
-
- You need to use the class member access operators if the friend function is a
- member of another class. For example:
-
- class A
- {
- public:
- int f() { /* ... */ }
- };
- class B
- {
- friend int A::f();
- };
-
- Friends of a base class are not inherited by any classes derived from that base
- class.
-
- "Scope of Class Names" is described on page Scope of Class Names.
-
-
- ΓòÉΓòÉΓòÉ 10.11.2. Friend Access ΓòÉΓòÉΓòÉ
-
- A friend of a class can access the private and protected members of that class.
- Normally you can only access theprivate members of a class through member
- functions of that class, and you can only access the protected members of a
- class through member functions of a class or classes derived from that class.
-
- Friend declarations are not affected by access specifiers.
-
- For more information on access, see also "Member Access"
-
-
- ΓòÉΓòÉΓòÉ 10.12. Related Information ΓòÉΓòÉΓòÉ
-
- "C++ Classes"
-
- "Inheritance"
-
-
- ΓòÉΓòÉΓòÉ 11. Chapter 11. C++ Overloading ΓòÉΓòÉΓòÉ
-
- This chapter introduces the concept of overloading in C++ and discusses the
- following topics:
-
- o Introduction to overloading
- o Overloading functions
- o Argument matching
- o Introduction to overloading operators.
- o Overloading unary operators
- o Overloading binary operators
- o Special overloaded operators
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 11.1. Introduction to Overloading ΓòÉΓòÉΓòÉ
-
- This chapter describes two distinct types of overloading: function overloading
- and operator overloading. Overloading enables you to redefine functions and
- most standard C++ operators. Typically, you overload a function or operator if
- you want to extend the operations the function or operator performs to
- different data types.
-
-
- ΓòÉΓòÉΓòÉ 11.2. Overloading Functions ΓòÉΓòÉΓòÉ
-
- You can overload a function by having multiple declarations of the same
- function name in the same scope. The declarations differ in the type and number
- of arguments in the argument list. When an overloaded function is called, the
- correct function is selected by comparing the types of the actual arguments
- with the types of the formal arguments.
-
- Consider a function print which displays a int value. You can overload the
- function print to display other types, for example, double and char*. You can
- have three functions with the same name, each performing a similar operation on
- a different data type.
-
- #include <iostream.h>
- void print(int i) { cout << " Here is int " <<
- i << endl;}
- void print(double f) { cout << " Here is float
- " << f << endl;}
- void print(char* c) { cout << " Here is char* "
- << c << endl;}
- void main() {
- print(10); // calls print(int)
- print(10.10); // calls print(double)
- print("ten"); // calls print(char*)
- }
-
-
- ΓòÉΓòÉΓòÉ 11.2.1. Declaration Matching ΓòÉΓòÉΓòÉ
-
- Two function declarations are identical if all of the following are true:
-
- o They have the same function name
- o They are declared in the same scope
- o They have identical argument lists.
-
- When you declare a function name more than once in the same scope, the second
- declaration of the function name is interpreted by the &xcomp. &xcompos2. as
- follows:
-
- o If the return type, argument types, and number of arguments of the two
- declarations are identical, the second declaration is considered a
- declaration of the same function as the first.
-
- o If only the return types of the two function declarations differ, the second
- declaration is an error.
-
- o If either the argument types or number of arguments of the two declarations
- differ, the function is considered to be overloaded.
-
-
- ΓòÉΓòÉΓòÉ 11.2.2. Restrictions on Overloaded Functions ΓòÉΓòÉΓòÉ
-
- The following are restrictions on overloaded functions:
-
- o Functions that differ only in return type cannot have the same name.
-
- o Two member functions that differ only in that one is declaredwith the keyword
- static and the other is not cannot have the same name.
-
- o A typedef is a synonym for another type, not a separate type. Thus, the
- following two declarations of spadina() are declarations of the same
- function:
-
- typedef int I;
- void spadina(float, int);
- void spadina(float, I);
-
- o A member function of a derived class is not in the same scope as a member
- function in a base class with the same name. A derived class member hides a
- base class member with the same name.
-
- o Arguments type that differ only in that one is a pointer * and the other is
- an array [ ] are identical. The following two declarations are equivalent:
-
- f(char*);
- f(char[10]);
-
-
- ΓòÉΓòÉΓòÉ 11.3. Argument Matching ΓòÉΓòÉΓòÉ
-
- When an overloaded function or overloaded operator is called, the &xcomp.
- &xcompos2. chooses the function declaration with the best match on all
- arguments from all the function declarations that are visible. The &xcomp.
- &xcompos2. compares the actual arguments of a function call with the formal
- arguments of all declarations of the function that are visible. For a best
- match to occur, the &xcomp. &xcompos2. must be able to distinguish a function
- that:
-
- o Has at least as good a match on all arguments as any other function with the
- same name
-
- o Has at least one better argument match than any other function with the same
- name.
-
- If no such function exists, the call is not allowed. There are three possible
- outcomes of a call to an overloaded function. The &xcomp. &xcompos2. can find
- the following:
-
- o An exact match
- o No match
- o An ambiguous match.
-
- An ambiguous match occurs when the actual arguments of the function call match
- more than one overloaded function.
-
- Argument matching can include performing standard and user-defined conversions
- on the arguments to match the actual arguments with the formal arguments. Only
- a single user-defined conversion is performed in a sequence of conversions on
- an actual argument. In addition, the best-matching sequence of standard
- conversions is performed on an actual argument. The best-matching sequence is
- the shortest sequence of conversions between two standard types. For example,
- the conversion:
-
- int -> float -> double
-
- can be shortened to the best-matching conversion sequence:
-
- int -> double
-
- because the conversion from int to double is allowed.
-
- Trivial conversions, do not affect the choice of conversion sequence.
-
-
- ΓòÉΓòÉΓòÉ 11.3.1. Sequences of Conversions ΓòÉΓòÉΓòÉ
-
- Sequences of conversions are considered in the following order:
-
- o An exact match in which the actual arguments match exactly (including a match
- with one or more trivial conversions) with the type and number of formal
- arguments of one declaration of the overloaded function
-
- o A match with promotions in which a match is found when one or more of the
- actual arguments is promoted
-
- o Match with standard conversions in which a match is found when one or more of
- the actual arguments is converted by a standard conversion
-
- o Match with user-defined conversions in which a match is found when one or
- more of the actual arguments is converted by an user-defined conversion
-
- o Match with ellipses.
-
- Match through promotion follows the rules for integral promotions
-
- Match through conversion follows the rules for standard conversions
-
- You can override an exact match by using an explicit cast. In the following
- example, the second call to f() matches with f(void*):
-
- void f(int);
- void f(void*);
- // .
- // .
- // .
- void main()
- {
- f(0xaabb); // matches f(int);
- f((void*) 0xaabb); // matches f(void*)
- }
-
- The implicit first argument for a nonstatic member function or operator is the
- this pointer The this pointer refers to the class object for which the member
- function is called. When you overload a nonstatic member function, the first
- implicit argument, the this pointer, is matched with the object or pointer used
- in the call to the member function. User-defined conversions are not applied in
- this type of argument matching for overloaded functions or operators.
-
- When you call an overloaded member function of class X using the . or ->
- operator, the this pointer has type X* const. The type of the this pointer for
- a constant object is const X* const. The type of the this pointer for a
- volatile object is volatile X* const.
-
- The class member access operators . (dot) and -> (arrow)
-
-
- ΓòÉΓòÉΓòÉ 11.3.2. Trivial Conversions ΓòÉΓòÉΓòÉ
-
- Functions cannot be distinguished if they have the same name and that have
- arguments that differ only in that one is declared as a reference to a type and
- the other is that type. Thus, you cannot have two functions with the same name
- and with arguments differing only in this respect. The following two
- declarations cannot be distinguished, and thus the second one causes an error:
-
- double f(double i); // declaration
- // .
- // .
- // .
- double f(double &i); // error
-
- However, functions with the same name having arguments that differ only in that
- one is a pointer or reference and the other is a pointer to const or const
- reference can be distinguished. Functions with the same name having arguments
- that differ only in that one is a pointer or reference and the other is a
- pointer to volatile or volatile reference can also be distinguished. Functions
- that have a volatile or const match are better than those that have a volatile
- or const mismatch.
-
- For more details on conversions see and "User-Defined Conversions"
-
-
- ΓòÉΓòÉΓòÉ 11.4. Introduction to Overloading Operators ΓòÉΓòÉΓòÉ
-
- You can overload one of the standard C++ operators by redefining it to perform
- a particular operation when it is applied to an object of a particular class.
- Overloaded operators must have at least one argument that has class type. An
- overloaded operator is called an operator function and is declared with the
- keyword operator preceding the operator. Overloaded operators are distinct from
- overloaded functions, but like overloaded functions, they are distinguished by
- the number and types of operands used with the operator.
-
-
- ΓòÉΓòÉΓòÉ 11.4.1. Overloading Operator Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for overloading an operator is:
-
- operator-function-name:
- operator operator
-
- where operator is a keyword and operator is one of :
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé + Γöé - Γöé * Γöé / Γöé % Γöé ^ Γöé & Γöé Γöé Γöé ~ Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ! Γöé = Γöé < Γöé > Γöé Γö╝= Γöé -= Γöé *= Γöé /= Γöé %= Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ^= Γöé &= Γöé Γöé= Γöé << Γöé >> Γöé <<= Γöé >>= Γöé == Γöé != Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé <= Γöé >= Γöé && Γöé ΓöéΓöé Γöé Γö╝+ Γöé -- Γöé , Γöé ->* Γöé -> Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé ( ) Γöé [ ] Γöé new Γöé deletΓöé Γöé Γöé Γöé Γöé Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- where ( ) is the function call operator and [ ] is the subscript operator.
-
- Consider the standard + (plus) operator. When this operator is used with
- operands of different standard types, the operators have slightly different
- meanings. For example, the addition of two integers is not implemented the same
- way as the addition of two floating-point numbers. C++ allows you to define
- your own meanings for the standard C++ operators when they are applied to class
- types. In the following example, a class called complx is defined to model
- complex numbers, and the + (plus) operator is redefined in this class to add
- two complex numbers.
-
- #include <iostream.h>
- class complx
- {
- double real,
- imag;
- public:
- complx( double real = 0., double imag = 0.); // constructor
- complx operator+(const complx&) const; // operator+()
- };
- // define constructor
- complx::complx( double r, double i )
- {
- real = r; imag = i;
- }
- // define overloaded + (plus) operator
- complx complx::operator+ (const complx& c) const
- {
- complx result;
- result.real = (this->real + c.real);
- result.imag = (this->imag + c.imag);
- return result;
- }
- void main()
- {
- complx x(4,4);
- complx y(6,6);
- complx z = x + y; // calls complx::operator+()
- }
-
-
- ΓòÉΓòÉΓòÉ 11.4.2. General Rules for Overloading Operators ΓòÉΓòÉΓòÉ
-
- The argument matching conventions and rules described
-
- You can overload both the unary and binary forms of:
-
- + _ * &
-
- When an overloaded operator is a member function, the first operand is matched
- against the class type of the overloaded operator. The second operand, if one
- exists, is matched against the argument in the overloaded operator call.
-
- When an overloaded operator is a nonmember function at least one operand must
- have class type. The first operand is matched against the first argument in the
- overloaded operator call.The second operand, if one exists, is matched against
- the second argument in the overloaded operator call.
-
-
- ΓòÉΓòÉΓòÉ 11.4.3. Operands ΓòÉΓòÉΓòÉ
-
- An overloaded operator must be either a member function, as shown in the
- following example:
-
- class X
- {
- public:
- X operator!();
- X& operator =(X&);
- X operator+(X&);
- };
- X X::operator!() { /* ... */ }
- X& X::operator=(X& x) { /* ... */ }
- X X::operator+(X& x) { /* ... */ }
-
- or take at least one argument of class type or a reference to class type, as
- shown below.
-
- class Y;
- {
- // .
- // .
- // .
- };
- class Z;
- {
- // .
- // .
- // .
- };
- Y operator!(Y& y);
- Z operator+(Z& z, int);
-
- Usually, overloaded operators are invoked using the normal operator syntax. You
- can also call overloaded operators explicitly. For example, for the class
- complx , described above, you can call the overloaded + (plus) operator either
- implicitly or explicitly as shown below.
-
- class complx
- {
- double real,
- imag;
- public:
- complx( double real = 0., double imag = 0.);
- complx operator+(const complx&) const;
- };
- // .
- // .
- // .
- void main()
- {
- complx x(4,4);
- complx y(6,6);
- complx u = x.operator+(y); // explicit call
- complx z = x + y; // implicit call to complx::operator+(
- )
- }
-
-
- ΓòÉΓòÉΓòÉ 11.4.4. Restrictions on Overloaded Operators ΓòÉΓòÉΓòÉ
-
- The following C++ operators cannot be overloaded:
-
- . .* :: ?:
-
- You cannot overload the preprocessing symbols # and ##.
-
- You cannot change the precedence, grouping, or number of operands of the
- standard C++ operators. For more details, see "Operator Precedence and
- Associativity"
-
- An overloaded operator (except for the function call operator) cannot have
- default arguments or ellipsis in the argument list.
-
- You must declare the overloaded =, [ ], ( ) and -> operators as nonstatic
- member functions to ensure that they receive lvalues as their first operands.
-
- The operators new and delete do not follow the general rules described in the
- above section. For further details, see overloading "new and delete"
-
- All operators except the = operator are inherited. For more details, see
- "Copying by Assignment" .
-
- Unless they are explicitly mentioned in "Special Overloaded Operators",
- overloaded unary and binary operators follow the rules outlined in "Unary" and
- "Binary" operators
-
- For details on standard C++ operators, see "Expressions and Operators"
-
-
- ΓòÉΓòÉΓòÉ 11.5. Overloading Unary Operators ΓòÉΓòÉΓòÉ
-
- You can overload a prefix unary operator by declaring a nonmember function
- taking one argument or a nonstatic member function taking no arguments.
-
- When you prefix a class object with an overloaded unary operator, for example:
-
- class X
- {
- // .
- // .
- // .
- };
- void main ()
- {
- X x;
- !x; // overloaded unary operator
- }
-
- the operator function call !x can be interpreted as:
-
- x.operator!( )
-
- or
-
- operator!(x)
-
- depending on the declarations of the operator function. If both forms of the
- operator function have been declared, argument matching determines which
- interpretation is used.
-
- For details on standard unary operators, see "Unary Expressions"
-
-
- ΓòÉΓòÉΓòÉ 11.6. Overloading Binary Operators ΓòÉΓòÉΓòÉ
-
- You can overload a binary operator by declaring a nonmember function taking two
- arguments or a nonstatic member function taking one argument.
-
- When you use a class object with an overloaded binary operator, for example:
-
- class X
- {
- // .
- // .
- // .
- };
- void main ()
- {
- X x;
- int y=10;
- x*y; // overloaded binary operator
- }
-
- the operator function call x*y can be interpreted as:
-
- x.operator*(y)
-
- or
-
- operator*(x,y)
-
- depending on the declarations of the operator function. If both forms of the
- operator function have been declared, argument matching determines which
- interpretation is used.
-
- For details on standard binary operators see "Binary Expressions"
-
-
- ΓòÉΓòÉΓòÉ 11.7. Special Overloaded Operators ΓòÉΓòÉΓòÉ
-
- The following overloaded operators do not fully follow the rules for unary or
- binary overloaded operators
-
- o Assignment
- o Function call
- o Subscripting
- o Class member access
- o Increment and decrement
- o new and delete.
-
-
- ΓòÉΓòÉΓòÉ 11.7.1. Assignment ΓòÉΓòÉΓòÉ
-
- You can only overload an assignment operator by declaring a nonstatic member
- function. The following example shows how you can overload the assignment
- operator for a particular class:
-
- class X
- {
- public:
- X();
- X& operator=(X&);
- X& operator=(int);
-
- // .
- // .
- // .
- };
- X& X::operator=(X& x) { /* ... */ }
- X& X::operator=(int i) { /* ... */ }
- // .
- // .
- // .
- void main()
- {
- X x1, x2;
- x1 = x2; // call x1.operator=(X&)
- x1 = 5; // call x1.operator=(int)
- }
-
- You cannot declare an overloaded assignment operator that is a nonmember
- function.
-
- Overloaded assignment operators are not inherited.
-
- If a copy assignment operator function is not defined for a class, the copy
- assignment operator function is defined by default as a memberwise assignment
- of the class members. If assignment operator functions exist for base classes
- or class members, these operators will be used when the &xcomp. generates
- default copy assignment operators.
-
- For details on standard assignment operators, see "Assignment Operators"
-
-
- ΓòÉΓòÉΓòÉ 11.7.2. Function Call ΓòÉΓòÉΓòÉ
-
- The function call has syntax of the form:
-
- postfix-expression (
- [expression-list]
- )
-
- and is considered a binary operator. The operands are postfix-expression and an
- optional expression-list. The operator function operator( ) must be defined as
- a nonstatic member function. You cannot declare an overloaded function call
- operator that is a nonmember function.
-
- If you make the following call for the class object x:
-
- x (arg1, arg2, arg3)
-
- it is interpreted as
-
- x.operator( )(arg1, arg2, arg3)
-
- Unlike all other overloaded operators, you can provide default arguments and
- ellipses in the argument list for the function call operator. For example:
-
- class X
- {
- public:
- X& operator() (int = 5);
- };
- // .
- // .
- // .
-
- For details on the standard function call operator, see "Function Call"
-
-
- ΓòÉΓòÉΓòÉ 11.7.3. Subscripting ΓòÉΓòÉΓòÉ
-
- An expression containing the subscripting operator has syntax of the form:
-
- postfix-expression [
- expression
- ]
-
- and is considered a binary operator. The operands are postfix-expression and
- expression. The operator function operator[ ] must be defined as a nonstatic
- member function. You cannot declare an overloaded subscript operator that is a
- nonmember function.
-
- A subscripting expression for the class object x:
-
- x [y]
-
- is interpreted as x.operator[ ](y). It is not interpreted as operator[ ](x,y)
- because it is defined as a nonstatic member function.
-
- For details on the standard subscripting operator see "Array Subscript"
-
-
- ΓòÉΓòÉΓòÉ 11.7.4. Class Member Access ΓòÉΓòÉΓòÉ
-
- An expression containing the class member access -> (arrow) operator has syntax
- of the form:
-
- postfix-expression -> name
-
- and is considered a unary operator. The operator function operator->( ) must be
- defined as a nonstatic member function.
-
- The following restrictions apply to class member access operators:
-
- o You cannot declare an overloaded arrow operator that is a nonmember function.
-
- o You cannot overload the class member access . (dot) operator.
-
- Consider the following example of overloading the -> (arrow) operator:
-
- class Y
- {
- public:
- void f();
- };
- class X
- {
- public:
- Y* operator->();
- };
- X x;
- // .
- // .
- // .
- x->f();
-
- Here x->f() is interpreted as:
-
- ( x.operator->( ) )-> f()
-
- x.operator->() must return either a reference to a class object or a class
- object for which the overloaded operator -> function is defined or a pointer to
- any class. If the overloaded operator -> function returns a class type, the
- class type must not be the same as the class declaring the function, and the
- class type returned must contain its own definition of an overloaded ->
- operator function.
-
- For details on the standard class member access arrow operator, see "Arrow"
-
-
- ΓòÉΓòÉΓòÉ 11.7.5. Increment and Decrement ΓòÉΓòÉΓòÉ
-
- The prefix increment operator ++ can be overloaded for a class type by
- declaring a nonmember function operator with one argument of class type or a
- reference to class type, or by declaring a member function operator with no
- arguments. In the following example, the increment operator is overloaded in
- both ways:
-
- class X
- {
- int a;
- public:
- operator++(); // member prefix increment operator
- };
- class Y { /* ... */ }
- operator++(Y& y); // nonmember prefix increment
- operator
- // .
- // .
- // .
- // Definitions of prefix increment operator functions
- // .
- // .
- // .
- void main()
- {
- X x;
- ++x; // x.operator++
- x.operator++(); // x.operator++
- operator++(y); // nonmember operator++
- ++y; // nonmember operator++
- }
-
- The postfix increment operator ++ can be overloaded for a class type by
- declaring a nonmember function operator operator++ ( ) with two arguments, the
- first having class type and the second having type int. Alternatively, you can
- declare a member function operator operator++ ( ) with one argument having type
- int. The &xcomp. uses the int argument to distinguish between the prefix and
- postfix increment operators. For implicit calls, the default value is zero. For
- example:
-
- class X
- {
- int a;
- public:
- operator++(int); // member postfix increment operator
- };
- operator++(X x, int i); // nonmember postfix increment
- operator
- // .
- // .
- // .
- // Definitions of postfix increment operator functions
- // .
- // .
- // .
-
- void main()
- {
- X x;
- x++; // x.operator++
- // default zero is supplied by compiler
- x.operator++(0); // x.operator++
- operator++(x,0); // nonmember operator++
- }
-
- The prefix and postfix decrement operators follow the same rules as their
- increment counterparts.
-
- For details on the standard postfix increment and decrement operators, see
- "Postfix Increment" and "Postfix Decrement" For details on the standard prefix
- increment and decrement operators, see "Prefix Increment" and "Prefix
- Decrement"
-
-
- ΓòÉΓòÉΓòÉ 11.7.6. new and delete ΓòÉΓòÉΓòÉ
-
- You can implement your own memory management scheme for a class by overloading
- the operators new and delete. The overloaded operator new must return a void*,
- and its first argument must have type size_t. size_t is defined in the standard
- header file <stddef.h>. The overloaded operator delete must return a void type,
- and its first argument must be void*. The second argument for the overloaded
- delete operator is optional and, if present, it must have type size_t. You can
- only define one delete operator function for a class.
-
- The size argument is required because a class may inherit an overloaded new
- operator. The derived class can be a different size than the base class. The
- size argument ensures that the correct amount of storage space is allocated or
- deallocated for the object.
-
- When new and delete are overloaded within a class declaration, they are static
- member functions whether they are declared with the keyword static or not.
- Thus, they cannot be virtual functions.
-
- You can access the standard, nonoverloaded versions of new and delete within a
- class scope containing the overloading new and delete operators by using the ::
- (scope) operator to provide global access.
-
- For details on the class member operators new and delete, see "Free Store" For
- details on the standard new and delete operators, see "new" and "delete and
- delete[]"
-
-
- ΓòÉΓòÉΓòÉ 11.8. Related Information ΓòÉΓòÉΓòÉ
-
- "Expressions and Operators"
-
- "Functions"
-
- "C++ Classes"
-
-
- ΓòÉΓòÉΓòÉ 12. Chapter 12. Special Member Functions ΓòÉΓòÉΓòÉ
-
- This chapter introduces the special member functions that are used to create,
- destroy, convert, initialize, and copy class objects. The following topics are
- discussed in this chapter:
-
- o Introduction to constructors and destructors
- o Constructors
- o Destructors
- o Free store
- o Temporary objects
- o User-defined conversions
- o Initialization by constructor
- o Copying class objects
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 12.1. Introduction to Constructors and Destructors ΓòÉΓòÉΓòÉ
-
- Because classes have complicated internal structures, including data and
- functions, object initialization and cleanup for classes is much more
- complicated than it is for simple data structures. Constructors and destructors
- are special member functions of classes that are used to construct and destroy
- class objects. Construction may involve memory allocation and initialization
- for objects. Destruction may involve cleanup and deallocation of memory for
- objects.
-
- Like other member functions, constructors and destructors are declared within a
- class declaration. They can be defined inline or external to the class
- declaration. Constructors can have default arguments. Unlike other member
- functions, constructors can have member initialization lists. The following
- restrictions apply to constructors and destructors:
-
- o Constructors and destructors do not have return types nor can they return
- values.
- o References and pointers cannot be used on constructors and destructors
- because you cannot obtain their addresses.
- o Constructors cannot be declared with the keyword virtual.
- o Constructors and destructors cannot be declared static, const, or volatile.
- o Unions and aggregate classes cannot contain class objects that have
- constructors or destructors.
-
- Constructors and destructors obey the same access rules as member functions.
- For example, if a constructor is declared with the keyword protected, only
- derived classes and friends can use it to create class objects.
-
- The &xcomp. &xcompos2. automatically calls constructors when defining class
- objects and calls destructors when class objects go out of scope. A constructor
- does not allocate memory for the class object its this pointer refers to, but
- may allocate storage for more objects that its class object refers to. If
- memory allocation is required for objects, constructors can explicitly call the
- new operator. During cleanup, a destructor may release objects allocated by
- the corresponding constructor. To release objects, use the delete operator.
-
- Derived classes do not inherit constructors or destructors from their base
- classes. Destructors can be declared with the keyword virtual.
-
- Constructors are also called when local or temporary class objects are created,
- and destructors are called when local or temporary objects go out of scope.
-
- You can call member functions from constructors or destructors. You can call a
- virtual function, either directly or indirectly, from a constructor or
- destructor. In this case, the function called is the one defined in the class
- or base class containing the constructor (or destructor) but not a function
- defined in any class derived from the class being constructed. This avoids the
- possibility accessing an unconstructed object from a constructor or destructor.
-
-
- ΓòÉΓòÉΓòÉ 12.2. Constructors ΓòÉΓòÉΓòÉ
-
- A constructor is a member function with the same name as its class. For
- example,
-
- class X
- {
- public:
- X(); // constructor for class X
- // .
- // .
- // .
- };
-
- Constructors are used to create, and can initialize, objects of their class
- type. Initialization of class objects using constructors is described in
- "Initialization by Constructor"
-
-
- ΓòÉΓòÉΓòÉ 12.2.1. Default Constructors ΓòÉΓòÉΓòÉ
-
- A default constructor is a constructor that either has no arguments, or, if it
- has arguments, all the arguments have default values. If no user-defined
- constructor exists for a class and one is needed, the &xcomp. creates a default
- constructor, with public access, for that class. It will not be created for a
- class that has any constant or reference type members.
-
- Like all functions, a constructor can have default arguments. They are used to
- initialize member objects. If default values are supplied, the trailing
- arguments can be omitted in the expression list of the constructor. For more
- details, see "Default Arguments" Note that if a constructor has any arguments
- that do not have default values, it is not a default constructor.
-
-
- ΓòÉΓòÉΓòÉ 12.2.2. Copy Constructors ΓòÉΓòÉΓòÉ
-
- A copy constructor is used to make a copy of one class object from another
- class object of the same class type. A copy constructor is called with a single
- argument that is a reference to its own class type. You cannot use a copy
- constructor with an argument of the same type as its class; you must use a
- reference. You can provide copy constructors with additional default arguments.
- If a user-defined copy constructor does not exist for a class and one is
- needed, the &xcomp. creates a copy constructor, with public access, for that
- class. It will not be created for a class if any of its members or base classes
- have an inaccessible copy constructor.
-
- The following code fragment shows two classes with constructors, default
- constructors, and copy constructors:
-
- class X
- {
- public:
- X(); // default constructor, no
- arguments
- X(int, int , int = 0); // constructor
- X(const X&); // copy constructor
- X(X); // error, illegal argument
- type
- };
- class Y
- {
- public:
- Y( int = 0); // default constructor with
- one
- // default argument
- Y(const Y&, int = 0); // copy constructor
- };
-
-
- ΓòÉΓòÉΓòÉ 12.2.3. Construction Order of Class Objects ΓòÉΓòÉΓòÉ
-
- If a class has a base class or members with constructors when it is
- constructed, the constructor for the base class is called, followed by any
- constructors for members. The constructor for the derived class is called last.
- Virtual base classes are constructed before nonvirtual base classes. When more
- than one base class exists, the base class constructors are called in the order
- that their classes appear in the base list, as shown in the following example.
- Note that the construction of class D involves construction of the base classes
- B1, B2, and B3. The construction of base class B2 involves the construction of
- its class B1 member object. Thus, when class B2 is constructed, the constructor
- for class B1 is called in addition to B2's own constructor:
-
- class B1 { public: B1();};
- class B2
- {
- public:
- B2();
- B1 b1obj;
- };
- class B3 { public: B3();};
- // .
- // .
- // .
- class D : public B1, public B2, public B3
- {
- public:
- D();
- ~D();
- };
- // .
- // .
- // .
- void main ()
- {
- D object;
- }
-
- In the above example, the constructors for object are called in the following
- order:
-
- B1(); // first base constructor declared
- B1(); // member constructor for B2::b1obj
- B2(); // second base constructor declared
- B3(); // last base constructor declared
- D(); // derived constructor called last
-
- As explained above, the second call to the constructor of B1 followed by the
- call to the constructor of B2 is part of the construction of B2.
-
- For more details, see "Construction Order of Derived Class Objects"
-
-
- ΓòÉΓòÉΓòÉ 12.2.4. Explicitly Constructing Objects ΓòÉΓòÉΓòÉ
-
- You cannot call constructors directly. You can use a function style cast to
- explicitly construct an object of the specified type. In the following example,
- a constructor is used as an initializer to create a named object.
-
- #include <iostream.h>
- class X
- {
- public:
-
- X (int, int , int = 0); // constructor with default
- argument
- private:
- int a, b, c;
- int f();
- };
- X::X (int i, int j, int k) { a = i; b = j; c = k; }
- // .
- // .
- // .
- void main ()
- {
- X xobject = X(1,2,3); // explicitly create and initialize
- // named object with constructor call
- }
-
-
- ΓòÉΓòÉΓòÉ 12.3. Destructors ΓòÉΓòÉΓòÉ
-
- A destructor is a member function with the same name as its class prefixed by
- a~(tilde). For example:
-
- class X
- {
- public:
- X(); // constructor for class X
- ~X(); // destructor for class X
- // .
- // .
- // .
- };
-
- A destructor takes no arguments and has no return type. You cannot take its
- address. Destructors cannot be declared const, volatile, or static. A
- destructor can be declared virtual or pure virtual. A union cannot have as a
- member an object of a class with a destructor.
-
- Destructors are usually used to deallocate memory and do other cleanup for a
- class object and its class members when the object is destroyed. A destructor
- is called for a class object when that object passes out of scope or is
- explicitly deleted.
-
- Class members that are class types can have their own destructors. Both base
- and derived classes can have destructors, although destructors are not
- inherited. If a base class or a member of a base class has a destructor and a
- class derived from that base class does not declare a destructor, a default
- destructor is generated. The default destructor calls the destructors of the
- base class and members of the derived class. Default destructors are generated
- with default public access.
-
- Destructors are called in the reverse order to constructors:
-
- 1. The destructor for a class object is called before destructors for members
- and bases are called.
- 2. Destructors for nonstatic members are called before destructors for base
- classes are called.
- 3. Destructors for nonvirtual base classes are called before destructors for
- virtual base classes are called.
-
- When an exception is thrown for a class object with a destructor, the
- destructor for the temporary object thrown is not called until control passes
- out of the catch block. For more details, see "Constructors and Destructors" in
- "Chapter 15. Exception Handling"
-
- Destructors are implicitly called when an automatic or temporary object passes
- out of scope. They are implicitly called at program termination for constructed
- external and static objects. Destructors are invoked when you use the delete
- operator for objects created with the new operator. For example:
-
- #include <string.h>
- class Y
- {
- private:
- char * string;
- int number;
- public:
- Y(const char* n,int a); // constructor
- ~Y() { delete string; } // destructor
- };
- Y::Y(const char* n, int a) // define class Y constructor
- {
- string = strcpy(new char[strlen(n) + 1 ], n);
- number = a;
- }
- void main ()
- {
- Y yobj = Y("somestring", 10); // create and initialize
- // object of class Y
- // .
- // .
- // .
- // destructor ~Y is called before control returns from
- main()
- }
-
- You can use a destructor explicitly to destroy objects, although it is not
- recommended. If an object has been placed at a specific address by the new
- operator, you can call the destructor of the object explicitly to destroy it.
- An explicitly called destructor cannot delete storage.
-
- Note: You can only call destructors for class types. You cannot call
- destructors for simple types. The call to the destructor in the following
- example causes an error:
-
- int * ptr;
- ptr -> int::~int(); // error
-
-
- ΓòÉΓòÉΓòÉ 12.4. Free Store ΓòÉΓòÉΓòÉ
-
- Free store is used for dynamic allocation of memory. The new and delete
- operators are used to allocate and deallocate free store, respectively. You can
- define your own versions of new and delete for a class by overloading them. You
- can supply the new and delete operators with additional arguments. When new and
- delete operate on class objects, the class member operator functions new and
- delete are called, if they have been declared.
-
- If you create a class object with the new operator, the operator function
- operator new() (if it has been declared) is called to create the object. An
- operator function operator new() for a class is always a static class member,
- even if it is not declared with the keyword static. The operator function
- operator new() has a return type void*. The first argument to the operator
- function operator new() must be the size of the object type and have type
- size_t. size_t is an implementation integral type defined in <stddef.h>.
-
- When you overload the new operator, you must declare it as a class member,
- returning type void*, with first argument size_t, as described above. You
- supply additional arguments in the declaration of the operator function
- operator new(). Values for these arguments are specified in an allocation
- expression by using the placement syntax. The following example shows two
- overloaded new operator functions.
-
- #include <stddef.h>
- class X
- {
- public:
- void* operator new(size_t);
- void* operator new(size_t, int);
- };
- // .
- // .
- // .
- void main ()
- {
- X* ptr1 = new X; // calls X::operator
- new(sizeof(X))
- X* ptr2 = new(10) X; // calls X::operator
- // new(sizeof(X),10)
- }
-
- The delete operator destroys an object created by the new operator. The operand
- of delete must be a pointer returned by new. If delete is called for an object
- with a destructor, the destructor is invoked before the object is deallocated.
-
- If you destroy a class object with the delete operator, the operator function
- operator delete() (if it has been declared) is called to destroy the object.
- An operator function operator delete() for a class is always a static member,
- even if it is not declared with the keyword static. The first argument to
- delete must have type void*. Because the operator function operator delete()
- has a return type void, it cannot return a value.
-
- When you overload the delete operator, you must declare it as class member,
- returning type void, with first argumenthaving type void*, as described above.
- You may supply an additional argument in the declaration of the operator
- function operator delete() having type size_t.You can only have one operator
- function operator delete() for a single class. The following example shows the
- declaration and use of the operator functions operator new() and operator
- delete():
-
- #include <stddef.h>
- class X
- {
- public:
- void* operator new(size_t);
- void operator delete(void*); // single argument
- };
- class Y
- {
- public:
- void operator delete(void*, size_t); // two arguments
- };
- // .
- // .
- // .
- void main ()
- {
- X* ptr = new X;
- delete ptr; // call X::operator delete(void*)
- Y* yptr;
- // .
- // .
- // .
- delete yptr; // call Y::operator delete(void*,
- size_t)
- // with size of Y as second argument
- }
-
- The result of trying to access a deleted object is undefined because the value
- of the object can change after deletion.
-
- If new and delete are called for a class object that does not declare the
- operator functions new and delete, or they are called for a nonclass object,
- the global operators new and delete are used. The global operators new and
- delete are provided in the C++ library.
-
- When you declare arrays of class objects, the global new and delete operators
- are used.
-
-
- ΓòÉΓòÉΓòÉ 12.5. Temporary Objects ΓòÉΓòÉΓòÉ
-
- It is sometimes necessary for the &xcomp. to create temporary objects.
- Temporary objects are used during reference initialization and during
- evaluation of expressions including standard type conversions, argument
- passing, function returns, and evaluation of the throw expression.
-
- When a temporary object is created to initialize a reference variable, the
- temporary object has the same scope as the reference variable. When a temporary
- object is created during the evaluation of an expression, it will exist until
- there is a break in the flow of control of the program.
-
- If a temporary object is created for a class with constructors, the &xcomp.
- calls the appropriate (matching) constructor to create the temporary object.
-
- When a temporary object is destroyed and a destructor exists, the &xcomp. calls
- the destructor to destroy the temporary object. When you exit from the scope in
- which the temporary object was created, it is destroyed. For example, if a
- reference is bound to a temporary object, the temporary object is destroyed
- when the reference passes out of scope. The following example shows two
- expressions in which temporary objects are constructed:
-
- class Y
- {
- public:
- Y(int);
- Y(Y&);
- ~Y();
- };
- Y add(Y y) { /* ... */ }
- // .
- // .
- // .
- void main ()
- {
- Y obj1(10);
- Y obj2 = add(Y(5)); // one temporary created
- obj1 = add(obj1); // two temporaries created
- }
-
- In the above example, a temporary object of class type Y is created to
- construct Y(5) before it is passed to the function add(). Because obj2 is being
- constructed, the function add() can construct its return value directly into
- obj2, so another temporary object is not created. A temporary object of class
- type Y is created when obj1 is passed to the function add(). Because obj1 has
- already been constructed, the function add() constructs its return value into a
- temporary object. This second temporary object is then assigned to obj1 using
- an assignment operator.
-
-
- ΓòÉΓòÉΓòÉ 12.6. User-Defined Conversions ΓòÉΓòÉΓòÉ
-
- User-defined conversions allow you to specify object conversions with
- constructors or with conversion functions. User-defined conversions are
- implicitly used in addition to standard conversions for conversion of
- initializers, functions arguments, function return values, expression operands,
- expressions controlling iteration, selection statements, and explicit type
- conversions. For more details, see "Type Conversions"
-
-
- ΓòÉΓòÉΓòÉ 12.6.1. Conversion by Constructor ΓòÉΓòÉΓòÉ
-
- You can call a class constructor with a single argument to convert from the
- argument type to the type of the class. For example:
-
- class Y
- {
- int a,b;
- char* name;
- public:
- Y(int i);
- Y(const char* n, int j = 0);
- };
- void add(Y);
- // .
- // .
- // .
- void main ()
- {
- // code equivalent code
- Y obj1 = 2; // obj1 = Y(2)
- Y obj2 = "somestring"; // obj2 = Y("somestring",0)
- obj1 = 10; // obj1 = Y(10)
- add(5); // add(Y(5))
- }
-
- At most one user-defined conversion, either a constructor or conversion
- function, is implicitly applied to a class object. When you call a constructor
- with an argument and you have not defined a constructor accepting that argument
- type, only standard conversions are used to convert the argument to another
- argument type acceptable to a constructor for that class. Other constructors or
- conversions functions are not called to convert the argument to a type
- acceptable to a constructor defined for that class.
-
-
- ΓòÉΓòÉΓòÉ 12.6.2. Conversion Functions ΓòÉΓòÉΓòÉ
-
- You can define a member function of a class, called a conversion function, that
- converts from the type of its class to another specified type. The syntax for a
- conversion function is:
-
- conversion-function-name:
- operator conversion-type-name
-
- conversion-type-name:
- type-specifier-list
- [ptr-operator]
-
- The conversion function specifies a conversion from the class type the
- conversion function is a member of, to the type specified by the
- conversion-type-name. Classes, enumerations, and typedef names cannot be
- declared or defined in the type-specifier-list.
-
- The following code fragment shows a conversion function called operator int():
-
- class Y
- {
- int b;
- public:
- operator int();
- };
- Y::operator int() {return b;}
-
- void f(Y obj )
- {
- // each value assigned is converted by Y::operator
- int()
- int i = int(obj);
- int j = (int)obj;
- int k = i + obj;
- }
-
- Conversion functions have no arguments, and the return type is implicitly the
- conversion type. Conversion functions can be inherited. You can have virtual
- conversion functions but not static ones.
-
- Only one user-defined conversion is implicitly applied to a single value.
- User-defined conversions must be unambiguous, or they are not called.
-
- If a conversion function is declared with the keyword const, the keyword has no
- affect on the function except for acting as a tie-breaker when there is more
- than one conversion function that could be applied. Specifically, if more than
- one conversion function could be applied, all of these functions are compared.
- If any of these functions is declared with the keyword const, const is ignored
- for the purposes of this comparison. If one of these functions is a best match,
- this function is applied. If there is no best match, the functions are compared
- again, but this time const is not ignored.
-
-
- ΓòÉΓòÉΓòÉ 12.7. Initialization by Constructor ΓòÉΓòÉΓòÉ
-
- A class object with a constructor must be explicitly initialized or have a
- default constructor. Explicit initialization using a constructor is the only
- way, except for aggregate initialization, to initialize nonstatic constant and
- reference class members.
-
- A class object that has no constructors, no virtual functions, no private or
- protected members and no base classes is called an aggregate.
-
-
- ΓòÉΓòÉΓòÉ 12.7.1. Explicit Initialization ΓòÉΓòÉΓòÉ
-
- Class objects with constructors can be initialized with a parenthesized
- expression list. This list is used as an argument list for the call of a
- constructor that is used to initialize the class. You can also call a
- constructor with a single initialization value using the = operator. Since this
- type of expression is an initialization not an assignment, the assignment
- operator function, if one exists, is not called. This value is used as a single
- argument for the call of a constructor. The type of the single argument must
- match the type of the first argument to the constructor. If the constructor has
- remaining arguments, these arguments must have default values. The syntax for
- an initializer that explicitly initializes a class object with a constructor
- is:
-
- initializer:
- (expression)
- = expression
-
- The following example shows the declaration and use of several constructors
- that explicitly initialize class objects:
-
- #include <iostream.h>
- class complx
- {
- double re, im ;
- public:
- complx(); // default constructor
- complx(const complx& c) {re = c.re; im = c.im;}
- // copy constructor
- complx( double r, double i = 0.0) {re = r; im =
- i;}
- // constructor with default trailing argument
- void display()
- {
- cout << "re = "<< re <<
- " im = " << im << endl;
- }
- };
- // .
- // .
- // .
- void main ()
- {
- complx one(1); // initialize with complx(double,
- double)
- complx two = one; // initialize with a copy of
- one
- // using complx::complx(const complx&)
- complx three = complx(3,4); // construct complx(3,4)
- // directly into three
- complx four; // initialize with default constructor
- complx five = 5; // complx(double, double) &
- construct
- // directly into five
- one.display();
- two.display();
- three.display();
- four.display();
- five.display();
- }
-
- The above example produces the following output:
-
- re = 1 im = 0
- re = 1 im = 0
- re = 3 im = 4
- re = 0 im = 0
- re = 5 im = 0
-
- Constructors can initialize their members in two different ways. A constructor
- can use the arguments passed to it to initialize member variables in the
- constructor definition:
-
- complx( double r, double i = 0.0) {re = r; im = i;}
-
- or a constructor can have an initializer list within the definition but prior
- to the function body:
-
- complx ( double r, double i = 0) : re(r), im(i) { /* ...
- */ }
-
- Both methods assign the argument values to the appropriate data members of the
- class. The second method must be used to initialize base classes from within a
- derived class in order to initialize constant and reference members and members
- with constructors.
-
-
- ΓòÉΓòÉΓòÉ 12.7.2. Initializing Base Classes and Members ΓòÉΓòÉΓòÉ
-
- You can initialize immediate base classes and derived class members that are
- not inherited from base classes by specifying initializers in the constructor
- definition prior to the function body. The syntax for a constructor initializer
- is:
-
- ctor-initializer:
- mem-initializer-list
-
- mem-initializer-list:
- mem-initializer
- mem-initializer ,
- mem-initializer-list
-
- mem-initializer:
- complete-class-name (
- [expression-list]
- )
- identifier (
- [expression-list]
- )
-
- In a constructor that is not inline, include the initialization list as part of
- the function definition, not as part of the class declaration. For example:
-
- class B1
- {
- int b;
- public:
- B1();
- B1(int i) : b(i) { /* ... */ } // inline
- constructor
- };
- class B2
- {
- int b;
- protected:
- B2();
- B2(int i); // noninline constructor
- };
- // B2 constructor definition including initialization list
- B2::B2(int i) : b(i) { /* ...*/ }
- // .
- // .
- // .
- class D : public B1, public B2
- {
- int d1, d2;
- public:
- D(int i, int j) : B1(i+1), B2(), d1(i) {d2 = j;}
- };
-
- If you do not explicitly initialize a base class or member that has
- constructors by calling a constructor, the &xcomp. will automatically
- initialize the base class or member with a default constructor. In the above
- example, if you leave out the call B2() in the constructor of class D (as shown
- below), a constructor initializer with an empty expression list is
- automatically created to initialize B2. Thus, the constructors for class D,
- shown above and below, will result in the same construction of an object of
- class D.
-
- class D : public B1, public B2
- {
- int d1, d2;
- public:
- // call B2() generated by compiler
- D(int i, int j) : B1(i+1), d1(i) {d2 = j;}
- };
-
- Note: You must declare base constructors with the access specifiers public or
- protected to enable a derived class to call them. For example:
-
- class B1
- {
- int b;
- public:
- B1();
- B1(int i) : b(i) { /* ... */ }
- };
- class B2
- {
- int b;
- protected:
- B2();
- B2(int i);
- };
- B2::B2(int i) : b(i) { /* ... */ }
- class B4
- {
- public:
- B4(); // public constructor for B4
- int b;
- private:
- B4(int); // private constructor for B4
- };
- // .
- // .
- // .
- class D : public B1, public B2, public B4
- {
- int d1, d2;
- public:
- D(int i, int j) : B1(i+1), B2(i+2) , B4(i) {d1 = i;
- d2 = j;}
- // error, attempt to access private constructor
- B4()
- D(int i, int j) : B1(i+1), B2(i+2) {d1 = i; d2 =
- j;}
- // valid, calls public constructor for B4
- };
-
-
- ΓòÉΓòÉΓòÉ 12.7.3. Construction Order of Derived Class Objects ΓòÉΓòÉΓòÉ
-
- When a derived class object is created using constructors, it is created in the
- following order:
-
- 1. Virtual base classes are initialized, in the order they appear in the base
- list.
- 2. Nonvirtual base classes are initialized, in declaration order.
- 3. Class members are initialized, in declaration order (regardless of their
- order in the initialization list).
- 4. The body of the constructor is executed.
-
- In the following code fragment, the constructor for class B1 is called before
- the member d1 is initialized. Thus, the value passed to the constructor
- forclass B1 is undefined.
-
- class B1
- {
- int b;
- public:
- B1();
- B1(int i) {b = i;}
- };
- // .
- // .
- // .
- class D : public B1
- {
- int d1, d2;
- public:
- D(int i, int j) : d1(i), B1(d1) {d2 = j;}
- // d1 is not initialized in call B1::B1(d1)
- };
-
-
- ΓòÉΓòÉΓòÉ 12.8. Copying Class Objects ΓòÉΓòÉΓòÉ
-
- You can copy one class object to another object of the same type by either
- assignment or initialization.
-
- Copy by assignment is implemented with an assignment operator function. If you
- do not define the assignment operator, it is defined as memberwise assignment.
-
- Copy by initialization is implemented with a copy constructor. If you do not
- define a copy constructor, it is defined as memberwise initialization of
- members of its class.
-
- Memberwise assignment and memberwise initialization mean that, if aclass has a
- member that is a class object, the assignment operator and copy constructor of
- that class object are used to implement assignment and initialization of the
- member.
-
-
- ΓòÉΓòÉΓòÉ 12.8.1. Copy Restrictions ΓòÉΓòÉΓòÉ
-
- A default assignment operator cannot be generated for a class that has:
-
- o A nonstatic constant or reference data member
-
- o A nonstatic data member or base class whose assignment operator is not
- accessible
-
- o A nonstatic data member or base class with no assignment operator and for
- which a default assignment operator cannot be generated.
-
- A default copy constructor cannot be generated for a class that has:
-
- o A nonstatic data member or base class whose copy constructor is not
- accessible
-
- o A nonstatic data member or base class with no copy constructor and for which
- a default copy constructor cannot be generated.
-
-
- ΓòÉΓòÉΓòÉ 12.8.2. Copy by Assignment ΓòÉΓòÉΓòÉ
-
- If you do not define an assignment operator and one is required, a default
- assignment operator is defined. If you do not define an assignment operator and
- one is not required, a default assignment operator is declared but not defined.
- If an assignment operator that takes a single argument of a class type exists
- for a class, a default assignment operator is not generated.
-
- Copy by assignment is used only in assignment.
-
- You can define an assignment operator for a class with a single argument that
- is a constant reference to that class type, only if all its base classes and
- members have assignment operators that accept constant arguments. For example:
-
- class B1
- {
- public:
- B1& operator=(const B1&);
- };
- class D: public B1
- {
- public:
- D& operator=(const D&);
- };
- D& D::operator=(const D& dobj) {D dobj2 = dobj; return
- dobj2;}
-
- Otherwise, you can define an assignment operator for a class with a single
- argument that is a reference to that class type. For example:
-
- class Z
- {
- public:
- Z& operator=( Z&);
- };
- Z& Z::operator=(Z& zobj) {Z zobj2 = zobj; return
- zobj2;}
-
- The default assignment operator for a class is a public class member. The
- return type is a reference to the class type it is a member of.
-
- For further details on standard C++ assignment operators, see "Assignment
- Operators" For further details on assignment operator functions, see
- "Assignment" in "Special Overloaded Operators"
-
-
- ΓòÉΓòÉΓòÉ 12.8.3. Copy by Initialization ΓòÉΓòÉΓòÉ
-
- You can define a copy constructor for a class. If you do not define a copy
- constructor and one is required, a default copy constructor is defined. If you
- do not define a copy constructor, and one is not required, a default copy
- constructor is declared but not defined. If a class has a copy constructor
- defined, a default copy constructor is not generated.
-
- Copy by initialization is used only in initialization.
-
- You can define a copy constructor for a class with a single argument that is a
- constant reference to a class type only if all its base classes and members
- have copy constructors that accept constant arguments. For example:
-
- class B1
- {
- public:
- B1(const B1&) { /* ... */ }
- };
-
- class D: public B1
- {
- public:
- D(const D&);
- };
- D::D(const D& dobj):B1(dobj) { /* ... */ }
-
- Otherwise, you can define a copy constructor with a single reference to a class
- type argument. For example,
-
- class Z
- {
- public:
- Z(Z&);
- };
- Z::Z(Z&) { /* ...*/ }
-
- The default copy constructor for a class is a public class member. For further
- details on copy constructors, see "Copy Constructors" and "Initialization by
- Constructor"
-
-
- ΓòÉΓòÉΓòÉ 12.9. Related Information ΓòÉΓòÉΓòÉ
-
- "C++ Classes"
-
- "Class Members and Friends"
-
- "C++ Overloading"
-
- "Inheritance"
-
-
- ΓòÉΓòÉΓòÉ 13. Chapter 13. Inheritance ΓòÉΓòÉΓòÉ
-
- This chapter described the following concepts and features of C++ :
-
- o Inheritance
- o Derivation
- o Inherited member access
- o Multiple inheritance
- o Virtual functions
- o Abstract classes.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 13.1. Inheritance ΓòÉΓòÉΓòÉ
-
- In C++, you can create classes from existing classes using the object-oriented
- programming technique called inheritance. Inheritance allows you to define an
- "is a" relationship between classes. When members are inherited, they can be
- used as if they are members of the class that inherits them.
-
-
- ΓòÉΓòÉΓòÉ 13.1.1. Single Inheritance ΓòÉΓòÉΓòÉ
-
- C++ implements inheritance through the mechanism of derivation. Derivation
- allows you to reuse code by creating new classes, called derived classes, that
- inherit properties from one or more existing classes, called base classes. A
- derived class inherits the properties, including data and function members, of
- its base class. In addition to inheriting base class members, you can add new
- data members and member functions to the derived class. You can also
- reimplement existing member functions or data by overriding base class members
- functions or data in the newly derived class.
-
- Suppose you have defined a shape class to describe and operate on geometric
- shapes. Now suppose you want to define a circle class. Because you have
- existing code that operates on the shape class, you can use inheritance to
- create the circle class. You can redefine operations in the derived circle
- class that were originally defined in the shape base class. When you manipulate
- an object of the circle class, these redefined function implementations will be
- used. For example:
-
- class shape
- {
- char* name;
- int xpoint, ypoint;
- public:
- virtual void rotate(int);
- virtual void draw();
- void display() const;
- };
-
- class circle: public shape // derive class circle from
- class shape
- {
- int xorigin, yorigin;
- int radius;
- public:
- void rotate(int);
- void draw();
- void display() const;
- };
- // .
- // .
- // .
-
- In the above example, class circle inherits the data members name, xpoint and
- ypoint as well as the member functions display(), rotate(), and draw() from
- class shape. Because the member functions rotate() and draw() are declared in
- class shape with the keyword virtual, you can provide an alternative
- implementation for them in class circle. You can also provide an alternative
- implementation for the nonvirtual member function display() in class circle.
- When you manipulate an argument of type circle using a pointer to shape, and
- call a virtual member function, the member function defined in the derived
- class will override the base class member function. A similar call to a
- nonvirtual member function will call the member function defined in the base
- class. In addition to inheriting the members of class shape, class circle has
- declared its own data members, xorigin, yorigin and radius.
-
- The key difference between virtual and nonvirtual member functions is that when
- you treat the circle class as if it were a shape, the implementations of the
- virtual functions rotate() and draw() defined in class circle are used rather
- than those originally defined in class shape. Because display() is a nonvirtual
- member function, the original implementation of display() defined in class
- shape is used.
-
-
- ΓòÉΓòÉΓòÉ 13.1.2. Multiple Inheritance ΓòÉΓòÉΓòÉ
-
- Multiple inheritance allows you to create a derived class that inherits
- properties from more than one base class. For example, in addition to the shape
- class, described above, you could also have a symbol class. Because a circle is
- both a shape and a symbol, you can use multiple inheritance to reflect this
- relationship. If the circle class is derived from both the shape and symbol
- classes, the circle class inherits properties from both classes.
-
- class symbol
- {
- char* language;
- char letter;
- int number;
- public:
- virtual void write();
- virtual void meaning();
- };
- class shape
- {
- char* name;
- int xpoint, ypoint;
- public:
- virtual void rotate(int);
- virtual void draw();
- void display() const;
- };
- class circle: public symbol, public shape
- {
- int xorigin, yorigin;
- int radius;
- public:
- void rotate(int);
- void draw ();
- void write();
- void meaning();
- void display() const;
- };
- // .
- // .
- // .
-
- In the above example, class circle inherits the members name, xpoint, ypoint,
- display(), rotate(), and draw() from class shape and also inherits the members
- language, letter, number, write(), and meaning() from class symbol.
-
- Because a derived class inherits members from all its base classes, ambiguities
- can result. For example, if two base classes have a member with the same name,
- the derived class cannot implicitly differentiate between the two members. Note
- that when using multiple inheritance, the access to names of base classes may
- be ambiguous.
-
-
- ΓòÉΓòÉΓòÉ 13.1.3. The Inheritance Design Process ΓòÉΓòÉΓòÉ
-
- Multiple inheritance allows you to have more than one base class for a single
- derived class. You can create an interconnected inheritance graph of inherited
- classes by using derived classes as base classes for other derived classes. You
- can build an inheritance graph through the process of specialization, in which
- derived classes are more specialized than their base classes. You can also work
- in the reverse direction and build an inheritance graph through generalization.
- If you have a number of related classes that share a group of properties, you
- can generalize and build a base class to embody them. The group of related
- classes become the derived classes of the new base class.
-
-
- ΓòÉΓòÉΓòÉ 13.1.4. Direct and Indirect Base Classes ΓòÉΓòÉΓòÉ
-
- A direct base class is a base class that appears directly as a base specifier
- in the declaration of its derived class. A direct base class is analogous to a
- parent in a hierarchical graph. In the above example, both shape and symbol are
- direct base classes of class circle.
-
- An indirect base class is a base class that does not appear directly in the
- declaration of the derived class but is available to the derived class through
- one of its base classes. An indirect base class is analogous to a grandparent
- or great grandparent or great great grandparent in a hierarchical graph. For a
- given class, all base classes that are not direct base classes are indirect
- base classes.
-
-
- ΓòÉΓòÉΓòÉ 13.1.5. Polymorphism ΓòÉΓòÉΓòÉ
-
- Polymorphic functions are functions that can be applied to objects of more than
- one type. In C++, polymorphic functions are implemented in two ways:
-
- o Overloaded functions are statically bound at compile time
-
- o C++ provides virtual functions. A virtual function is a function that can be
- called for a number of different user-defined types that are related through
- derivation. Virtual functions are bound dynamically at run time.
-
- Typically, a base class has several derived classes, each requiring its own
- customized version of a particular operation. It is difficult for a base class
- to implement member functions that are useful for all its derived classes. A
- base class would have to determine which derived class an object belonged to
- before it could execute the applicable code for that object. When a virtual
- function is called, the &xcomp. executes the function implementation associated
- with the object that the function is called for. The implementation of the base
- class is only a default that is used when the derived class does not contain
- its own implementation.
-
-
- ΓòÉΓòÉΓòÉ 13.2. Derivation ΓòÉΓòÉΓòÉ
-
- Inheritance is implemented in C++ through the mechanism of derivation.
- Derivation allows you to derive a class, called a derived class, from another
- class, called a base class.
-
- In the declaration of a derived class you list the base classes of the derived
- class. The derived class inherits its members from these base classes. All
- classes that appear in the list of base classes must be previously defined
- classes.
-
- class W
- {
- public:
- int a,b;
- };
- class Z: public W
- {
- public:
- int c,d;
- };
- // .
- // .
- // .
-
- Incompletely declared classes are not allowed in base lists. For example:
-
- class X; // incomplete declaration of class X
- class Y: public X // error
- {
- // .
- // .
- // .
- };
-
- When you derive a class, the derived class inherits class members of the base
- class. You can refer to inherited members (base class members) as if they were
- members of the derived class. For example:
-
- class base
- {
- public:
- int a,b;
- };
- class derived : public base
- {
- public:
- int c;
- };
- void main()
- {
- derived d;
- d.a = 1; // base::a
- d.b = 2; // base::b
- d.c = 3; // derived:
- }
-
- The derived class can also add new class members and redefine existing base
- class members. In the above example, the two inherited members, a and b, of the
- derived class d, in addition to the derived class member c, are assigned
- values. If you redefine base class members in the derived class, you can still
- refer to the base class members by using the :: (scope) operator. For example:
-
- #include <iostream.h>
- class base
- {
- public:
- char* name;
- void display(char* i) {cout << i <<
- endl;}
- };
- class derived : public base
- {
- public:
- char* name;
- void display(char* i){cout << i <<
- endl;}
- };
- void main()
- {
- derived d; // create derived class object
- d.name = "Derived Class"; // assignment to derived:
- d.base:="Base Class"; // assignment to base:
- // call derived:::name)
- d.display(d.name);
- // call base:::name)
- d.base::display(d.base::name);
- }
-
- The :: (scope) operator is described on page Scope Operator.
-
- You can manipulate a derived class object as if it were a base class object.
- You can use a pointer or a reference to a derived class object in place of a
- pointer or reference to its base class. For example, you can pass a pointer or
- reference to a derived class object D to a function expecting a pointer or
- reference to the base class of D. You do not need to use an explicit cast to
- achieve this; a standard conversion is performed. You can implicitly convert a
- pointer to a derived class to point to a base class. You can also implicitly
- convert a reference to a derived class to a reference to a base class.
-
- In the following example, d, a pointer to a derived class object, is assigned
- to bptr, a pointer to a base class object. A call is made to display() using
- bptr. Even though bptr has a type of pointer to base, in the body of display()
- the name member of derived is manipulated:
-
- #include <iostream.h>
- class base
- {
- public:
- char* name;
- void display(char* i) {cout << i <<
- endl;}
- };
- class derived : public base
- {
- public:
- char* name;
- void display(char* i){cout << i <<
- endl;}
- };
- void main()
- {
- derived d;
-
- // standard conversion from derived* to base*
- base* bptr = &d;
- // call base:::name)
- bptr->display(bptr->name);
- }
-
- The reverse case is not allowed. You cannot implicitly convert a pointer or a
- reference to a base class object to a pointer or reference to a derived class.
-
- If a member of a derived class and a member of a base class have the same name,
- the base class member is hidden in the derived class. If a member of a derived
- class has the same name as a base class, the base class name is hidden in the
- derived class. In both cases, the name of the derived class member is called
- the dominant name.
-
-
- ΓòÉΓòÉΓòÉ 13.2.1. Derivation Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for the list of base classes is:
-
- base-spec:
- base-list
-
- base-list:
- base-specifier
- base-list, base-specifier
-
- base-specifier:
- complete-class-name
- virtual
- [access-specifier]
- complete-class-name
- access-specifier
- [virtual]
- complete-class-name
-
- The complete-class-name must be a class that has been previously declared in a
- class declaration.
-
- An access-specifier is one of public, private,and protected.
-
- virtual is a keyword that can be used to declare virtualbase classes.
-
- For a complete summary of class declaration grammar including member and base
- class grammar, see "Class Declaration Grammar Summary" in Appendix B
-
- The following example shows the declaration of the derived class D and the base
- classes V, B1, and B2. The class B1 is both a base class and a derived class
- because it is derived from class V and is a base class for D.
-
- class V { /* ... */ };
- class B1 : virtual public V { /* ... */ };
- class B2 { /* ... */ };
- class D : public B1, private B2 { /* ... */ };
-
-
- ΓòÉΓòÉΓòÉ 13.3. Inherited Member Access ΓòÉΓòÉΓòÉ
-
- Access specifiers , control the level of access to noninherited class members.
- The access for an inherited member is controlled in three ways:
-
- o When you declare a member in a base class, you can specify a level of access
- using the keywords public, private, and protected .
-
- o When you derive a class you can specify the access level for the base class
- in the base list.
-
- o You can also restore the access level of inherited members.
-
- Resolution of member names does not depend on the level of access associated
- with each class member. Consider the following example:
-
- class A {
- private:
- int a;
- };
- class B {
- public:
- int a;
- };
- class C : public A, public B {
- void f() { a = 0; } // ambiguous - is it
- A::a or B::a?
- };
-
- In this example, class A has a private member a, and class B has a public
- member a. Class C is derived from both A and B. C does not have access to A:
- but a in the body of f() can still resolve to either A: or B::a. Thus, a is
- ambiguous in the body of f().
-
-
- ΓòÉΓòÉΓòÉ 13.3.1. Protected Members ΓòÉΓòÉΓòÉ
-
- If a class is derived publicly from a base class, a protected static base class
- member can be accessed by members and friends of any classes derived from that
- base class. A protected nonstatic base class member can be accessed by members
- and friends of any classes derived from that base class by using one of the
- following:
-
- o A pointer to a directly or indirectly derived class
-
- o A reference to a directly or indirectly derived class
-
- o An object of a directly or indirectly derived class.
-
- If a class is derived privately from a base class, all protected base class
- members become private members of the derived class.
-
- The access specifier protected is also described in "Access Specifiers"
-
-
- ΓòÉΓòÉΓòÉ 13.3.2. Derivation Access of Base Classes ΓòÉΓòÉΓòÉ
-
- When you declare a derived class, an access specifier can precede each base
- class in the base list of the derived class. This does not alter the access
- attributes of the individual members of a base class as seen by the base class,
- but allows the derived class to adjust the access attributes of the members of
- a base class. You can derive classes using any of the three access specifiers:
-
- o In a public base class, public and protected members of the base class remain
- publicand protected members of the derived class.
-
- o In a private base class, public and protected members of the base class
- become private members of the derived class.
-
- o In a protected base class, public and protected members of the base class are
- protected members of the derived class.
-
- In all cases, private members of the base class remain private. Private members
- of the base class cannot be used by the derived class unless friend
- declarations within the base class explicitly grant access to them.
-
- In the following example, class d is derived publicly from class b. Class b is
- declared a public base class by this declaration.
-
- class b
- {
- // .
- // .
- // .
- };
- class d : public b // public derivation
- {
- // .
- // .
- // .
- };
-
- You can use both a structureand a class as base classes in the base list of a
- derived class declaration. If the base class is declared with the keyword
- class, its default access specifier in the base list of a derived class is
- private. If the base class is declared with the keyword struct, its default
- access specifier in the base list of a derived class is public. In the
- following example, private derivation is used by default because no access
- specifier is used in the base list.
-
- struct bb
- {
- // .
- // .
- // .
- };
- class dd : bb // private derivation
- {
- // .
- // .
- // .
- };
-
- Members and friends of a class can implicitly convert a pointer to an object of
- that class to a pointer to either:
-
- o A direct private base class
- o A protected base class (either direct or indirect).
-
-
- ΓòÉΓòÉΓòÉ 13.3.3. Access Declarations ΓòÉΓòÉΓòÉ
-
- You can restore access to members of a base class using an access declaration.
- It allows you to change the access of a public member of a private or protected
- base class back to public. You can also change the access of a protected member
- of a private base class back to protected. Access is modified by using the base
- class member qualified name in the public or protected declarations of the
- derived class.
-
- You only use access declarations to restore base class access. You cannot
- change the access to a member to give it more access than it was originally
- declared with. You cannot change the access of a private member to public or to
- protected. You cannot adjust the access of a protected member to public.
-
- An access declaration cannot be used to restrict access to a member that is
- accessible in a base class.
-
- It is redundant to adjust the access to a public member of a public base class
- topublic, or to adjust the access to a protected member of a protected base
- class to protected.
-
- In the following example, the member b of the base class base is declared
- public in its base class declaration. Class derived is derived privately from
- class base. The access declaration in the public section of class derived
- restores the access level of the member b back to public.
-
- #include <iostream.h>
- class base
- {
- char a;
- public:
- char c, b;
- void bprint();
- };
-
- class derived: private base
- {
- char d;
- public:
- char e;
- base::b; // restore access to b in derived
- void dprint();
- derived(char ch) { base::b = ch;}
- };
-
- void print(derived& d)
- {
- cout << " Here is d " << d.b <<
- endl;
- }
-
- void main()
- {
- derived obj('c');
- print(obj);
- }
-
- The external function print(derived&) can use the member b of base because the
- access of b has been restored to public. The external function print(derived&)
- can also use the members e and dprint() because they are declared with the
- keyword public in the derived class. The derived class member dprint() can use
- the members of its own class, d and e, in addition to the inherited members, b,
- c, and bprint(), that are declared with the keyword public in the base class.
- The base class member bprint() can use all the members of its own class, a, b,
- and c.
-
- Access declarations can only be used to adjust the access of a member of a base
- class. The base class that an access declaration appears in can be directly or
- indirectly inherited by the derived class. You can also use an access
- declaration in a nested class. For example:
-
- class B
- {
- public:
- class N // nested class
- {
- public:
- int i; // public member
- };
- };
- class D: private B::N // derive privately
- {
- public:
- B::N:
- :i; // restores access to public
- };
-
- You cannot adjust the access to a base class member if a member with the same
- name exists in a class derived from that base class.
-
- You cannot convert a pointer to a derived class object to a pointer to a base
- class object if the base class is private or protected. For example:
-
- class B { /* ... */ };
- class D : private B { /* ... */ }; // private base
- class
- void main ()
- {
- D d;
- B* ptr;
- ptr = &d; // error
- }
-
- If you use an access declaration to adjust the access to an overloaded
- function, the access is adjusted for all functions with that name in the base
- class.
-
-
- ΓòÉΓòÉΓòÉ 13.3.4. Access Resolution ΓòÉΓòÉΓòÉ
-
- Access resolution is the process by which the accessibility of a particular
- class member is determined. Accessibility is dependent on the context. For
- example, a class member can be accessible in a member function but inaccessible
- at file scope. The following describes the access resolution procedure used by
- the &xcomp. &xcompos2..
-
- In general, two "scopes" must be established before access resolution is
- applied. These scopes reduce an expression or declaration into a simplified
- construct to which the access rules (described in "Member Access" ) are
- applied. These scopes are:
-
- o Call scope, the scope that encloses the expression or declaration that uses
- the class member.
-
- o Reference scope, the scope that identifies the class.
-
- For example, in the following code:
-
- class B { int member; }; // declaration
- class A : B {} // declaration
- void main()
- {
- A aobject; // declaration
- aobject.member = 10; // expression
- }
-
- the reference scope for member is the type of aobject, that is class type A.
-
- Reference scope is chosen by simplifying the expression (or declaration)
- containing the member. An expression can be thought of as being reduced to a
- simple expression of the form obj.member where obj is the reference scope.
- Reference scope is selected as follows:
-
- o If the member is qualified with . or ->, the reference scope is the type of
- the object that is immediately to the left of the . or -> operator closest to
- the member. Unqualified members are treated as if they are qualified with
- this->.
-
- o If the member is a type member or a static member and is qualified with ::,
- the reference scope is the type immediately to the left of the :: operator
- closest to the member.
-
- o Otherwise, the reference scope is the call scope.
-
- The call scope and the reference scope determine the accessibility of a class
- member. Once these scopes are resolved, the effective access of the member is
- determined. Effective access is the access of the member as it is seen from
- the reference scope. It is determined by taking the original access of the
- member in its scope as the effective access and changing it as the class
- hierarchy is traversed from the member's class to the reference scope.
- Effective access is altered as the class hierarchy is traversed for each
- derivation by the following:
-
- o The derivation access of a base class (see "Derivation Access of Base
- Classes" )
-
- o Access declarations that are applied to the members (see "Access
- Declarations" )
-
- o Friendships that are granted to the call scope (see "Member Access" ).
-
- After effective access is determined for a member, the access rules (described
- in "Member Access" ) are applied as if the effective access were the original
- access of the member. A member is only accessible is if the access rules say
- that it is.
-
- The following example demonstrates the access resolution procedure.
-
- class A
- {
- public:
- int a;
- };
- class B : private A
- {
- friend void f (B*);
- };
- void f(B* b)
- {
- b->a = 10; // is 'a' accessible to f(B*) ?
- }
- // .
- // .
- // .
-
- The following steps occur in order to determine the accessibility of A: in
- f(B*):
-
- 1. The call scope and reference scope of the expression b->a are determined.
- :ol2.
-
- 2. The call scope is the function f(B*).
-
- 3. The reference scope is class B.
-
- 4. The effective access of member a is determined
-
- 5. Because the original access of the member a is public in class A, the
- initial effective access of a is public.
-
- 6. Because B inherits from A privately, the effective access of a inside class
- B is private.
-
- 7. Because class B is the reference scope, the effective access procedure
- stops here. The effective access of a is private.
-
- 8. The access rules are applied.
-
- 9. The rules state that a private member may be accessed by a friend or a
- member of the member's class. Because f(B*) is a friend of class B, f(B*)
- can access the private member a.
-
-
- ΓòÉΓòÉΓòÉ 13.3.5. Access Summary ΓòÉΓòÉΓòÉ
-
- The following example demonstrates inherited member access rules.
-
- class B
- {
- int a;
- public:
- int b,c;
- void f(int) {}
- protected:
- int d;
- void g(int) {}
- };
- class D1 : public B
- {
- int a;
- public:
- int b;
- void h(int i )
- {
- g(i); // valid, protected B::g(int)
- B::b = 10; // valid, B::b (not local
- b)
- d = 5 ; // valid, protected B::d
- }
- };
- class D2 : private B
- {
- int e;
- public:
- B::c; // modify access to B:
- void h(int i) { d = 5; } // valid,protected
- B::d
- };
- void main( )
- {
-
- int i= 1; // declare and initialize local variable
- D1 d1; // create object of class d1
- D2 d2; // create object of class d2
-
- d1.a = 5; // error, D1::a is private in class
- D1
- d2.b = 10; // error, B::b is inherited private
- to
- // derived class D2
- d2.c = 5; // valid, modified access from private
- to public d2.B:=5; // valid, public
- B:
- d1.c = 5; // valid, B:is inherited publicly
- d1.d = 5; // error, B::d is protected in base
- class
- d2.e = 10; // error, private D2::e
- d1.g(i); // error, g(int) is protected in base
- class
- d1.h(i); // valid
- d2.h(i); // valid
- }
-
- Access rules for multiple base classes are described in "Multiple Access"
-
-
- ΓòÉΓòÉΓòÉ 13.4. Multiple Inheritance ΓòÉΓòÉΓòÉ
-
- You can derive a class from more than one base class. Deriving a class from
- more than one direct base classes is called multiple inheritance . In the
- following example, classes A, B and C are direct base classes for the derived
- class X:
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- class A { /* ... */ };
- class B { /* ... */ };
- class C { /* ... */ };
- class X : public A, private B, public C { /* ... */ };
-
- The order of derivation is relevant only to determine the order of default
- initialization by constructors and cleanup by destructors. For more details,
- see "Initialization by Constructor"
-
- A direct base class cannot appear in the base list of a derived class more than
- once:
-
- class B1 { /* ... */ }; // direct base
- class
- class D : public B1, private B1 { /* ... */ }; // error
-
- However, a derived class can inherit an indirect base class more than once, as
- shown in the following example :
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- class L { /* ... */ }; // indirect base
- class
- class B2 : public L { /* ... */ };
- class B3 : public L { /* ... */ };
- class D : public B2, public B3 { /* ... */ }; // valid
-
- In the above example, class D inherits the indirect base class L once through
- class B1 and once through class B2. However, this may lead to ambiguities
- because two objects of class L exist, and both are accessible through class D.
- You can avoid this ambiguity by referring to class L using a qualified class
- name. For example:
-
- B2:
-
- or
-
- B3:
-
- You can also avoid this ambiguity by using the base specifier virtual to
- declare a base class.
-
-
- ΓòÉΓòÉΓòÉ 13.4.1. Virtual Base Classes ΓòÉΓòÉΓòÉ
-
- If you have an inheritance graph in which two or more derived classes have a
- common base class, you can use a virtual base class to ensure that the two
- classes share a single instance of the base class rather than two separate
- copies.
-
- In the following example, an object of classD has two distinct objects of
- classL, one through class B1 and another through class B2. You can use the
- keyword virtual in front of the base class specifiers in the base lists
- ofclasses B1 and B2 to indicate that only one class L, shared by class B1 and
- classB2, exists. For example :
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- class L { /* ... */ }; // indirect base class
- class B1 : virtual public L { /* ... */ };
- class B2 : virtual public L { /* ... */ };
- class D : public B1, public B2 { /* ... */ }; // valid
-
- By using the keyword virtual in this example, an object of class D inherits
- only one object of class L.
-
- As well, a derived class can have both virtual and nonvirtual base classes. For
- example :
-
- Artwork from Interleaf needs to be redrawn or included
- from anencapsulated poststript file.
-
- class V { /* ... */ };
- class B1 : virtual public V { /* ... */ };
- class B2 : virtual public V { /* ... */ };
- class B3 : public V { /* ... */ };
- class D : public B1, public B2, public B3 { /* ... */
- };
-
- In the above example, class D has two objects of class V, one that is shared by
- classes B1 and B2 and one through class B3.
-
-
- ΓòÉΓòÉΓòÉ 13.4.2. Multiple Access ΓòÉΓòÉΓòÉ
-
- If you have an inheritance graph containing virtual base classes and a name can
- be reached through more than one path, the name is accessed through the path
- that gives the most access. For example:
-
- class L { public: void f(); };
- class B1 : private virtual L { /* ... */ };
- class B2 : public virtual L { /* ... */ };
- class D : public B1, public B2
- {
- public:
- void f() {L::f();} // L::f() is accessed
- through
- B2
- // and is public
- };
-
- In the above example, the function f() is accessed through class B2. Because
- class B2 is inherited publicly and class B1 is inherited privately, class B2
- offers more access.
-
-
- ΓòÉΓòÉΓòÉ 13.4.3. Accessible Base Classes ΓòÉΓòÉΓòÉ
-
- An accessible base class is a publicly derived base class that is neither
- hidden nor ambiguous in the inheritance hierarchy.
-
-
- ΓòÉΓòÉΓòÉ 13.4.4. Ambiguous Base Classes ΓòÉΓòÉΓòÉ
-
- When you derive classes, ambiguities can result if base and derived classes
- have members with the same names. Access to a base class member is ambiguous if
- you use a name or qualified namethat does not refer to a unique function,
- object, type or enumerator. The declaration of a member with an ambiguous name
- in a derived class is not an error. The ambiguity is only flagged as an error
- if you use the ambiguous member name.
-
- For example, if two base classes have a member of the same name, an attempt to
- access the member by the derived class is ambiguous. You can resolve ambiguity
- by qualifying a member with its class name using the scope operator.
-
- class B1
- {
- public:
- int i;
- int j;
- int g( );
- };
- class B2
- {
- public:
- int j;
- int g( );
- };
- // .
- // .
- // .
- class D : public B1, public B2
- {
- public:
- int i;
- };
- void main ()
- {
- D dobj;
- D *dptr = &dobj;
- dptr -> i = 5; // valid, D:
- :i
- dptr -> j = 10; // error, ambiguous reference
- to j
- dptr->B1::j = 10; // valid, B1::j
- dobj.g( ); // error, ambiguous reference
- to g( )
- dobj.B2::g( ); // valid, B2::g( )
- }
-
- The &xcomp. &xcompos2. checks for ambiguities at compile time. Because
- ambiguity checking occurs before access control or type checking, ambiguities
- may result even if only one of several members with the same name is accessible
- from the derived class.
-
- Conversions (either implicit or explicit) from a derived class pointer or
- reference to a base class pointer or reference, must refer unambiguously to the
- same accessible base class object. For example:
-
- class W { /* ... */ };
- class X : public W { /* ... */ };
- class Y : public W { /* ... */ };
- class Z : public X, public Y { /* ... */ };
- void main ()
- {
- Z z;
- X* xptr = &z; // valid
- Y* yptr = &z; // valid
- W* wptr = &z; // error, ambiguous reference to
- class W
- // X's W or Y's W ?
- }
-
- You can use virtual base classes to avoid ambiguous reference. For example:
-
- class W { /* ... */ };
- class X : public virtual W { /* ... */ };
- class Y : public virtual W { /* ... */ };
- class Z : public X, public Y { /* ... */ };
- void main ()
- {
- Z z;
- X* xptr = &z; // valid
- Y* yptr = &z; // valid
- W* wptr = &z; // valid, W is virtual therefore
- only one
- // W subobject exists
- }
-
- For more details, see "Virtual Base Classes"
-
-
- ΓòÉΓòÉΓòÉ 13.5. Virtual Functions ΓòÉΓòÉΓòÉ
-
- In C++, dynamic binding is supported by the mechanism of virtual functions.
- Virtual functions must be members of a class. Use virtual functions when you
- expect a class to be used as a base class in a derivation and when the
- implementation of the function may be overridden in the derived class. You can
- declare a member function with the keyword virtual in its class declaration.
- For example:
-
- class B
- {
- int a,b,c;
- public:
- virtual int f();
- };
- // .
- // .
- // .
-
- You can reimplement a virtual member function, like any member function, in any
- derived class. The implementation that is executed when you make a call to a
- virtual function depends on the type of the object for which it is called. If a
- virtual member function is called for a derived class object and the function
- is redefined in the derived class, the definition in the derived class is
- executed. In this case, the redefined derived class function is said to
- override the base class function. This occurs even if the access to the
- function is through a pointer or reference to the base class. If you call a
- virtual function with a pointer that has base class type but points to a
- derived class object, the member function of the derived class is called.
- However, if you call a nonvirtual function with a pointer that has base class
- type, the member function of the base class is called regardless of whether the
- pointer points to a derived class object. For example
-
- class B
- {
- public:
- virtual int f();
- virtual int g();
- int h();
- };
- class D : public B
- {
- public:
- int f();
- int g(char*); // hides B::g()
- int h();
- };
- // .
- // .
- // .
- void main ()
- {
- D d;
- B* bptr = &d;
-
- bptr->f(); // calls D::f() because f() is
- virtual
- bptr->h(); // calls B::h() because h() is
- nonvirtual
- bptr->g(); // calls B::g()
- d.g(); // error, wrong number and type of
- arguments
- d.g("string"); // calls D::g(char*)
- }
-
- If the argument types or the number of arguments of the two functions are
- different, the functions are considered different, and the function in the
- derived class does not override the function in the base class. The function in
- the derived class hides the function in the base class.
-
- It is an error to make only the return types of two functions with the same
- name different. For more details, see "Return Values"
-
- A virtual function cannot be global orstatic because, by definition, a virtual
- function is a member function of a base class and relies on a specific object
- to determine which implementation of the function is called.
-
- You can declare a virtual function to be a friend of another class.
-
- If a function is declared virtual in its base class, it can still be accessed
- directly using the :: (scope) operator. In this case, the virtual function call
- mechanism is suppressed and the function implementation defined in the base
- class is used. In addition, if you do not redefine a virtual member function in
- a derived class, a call to that function uses the function implementation
- defined in the base class.
-
- A virtual function must be one of the following:
-
- o Defined
- o Declared pure
- o Defined and declared pure.
-
- A base class containing one or more pure virtual member functions is called an
- abstract class.
-
-
- ΓòÉΓòÉΓòÉ 13.5.1. Ambiguous Virtual Function Calls ΓòÉΓòÉΓòÉ
-
- It is an error to override one virtual function with two or more ambiguous
- virtual functions. This can happen in a derived class that inherits from two
- nonvirtual bases that are derived from a virtual base class. For example:
-
- class V
- {
- public:
- virtual void f() { /* ... */ };
- };
- class A : virtual public V
- {
- void f() { /* ... */ };
- };
- class B : virtual public V
- {
- void f() { /* ... */ };
- };
- class D : public B { /* ... */ }; // error
- void main ()
- {
- D d;
- V* vptr = &d;
- vptr->f(); // which f(), A::f() or B::f()
- ?
- }
-
- In class A, only A: will override V:. Similarly, in class B, only B: will
- override V:. However, in class D, both A: and B: will try to override V:. This
- is not allowed because it is not possible to decide which function to call if a
- D object is referenced with a pointer to class V, as shown in the above
- example. Because only one function can override a virtual function, the &xcomp.
- &xcompos2. flags this type of situation as an error.
-
- A special case occurs when the ambiguous overriding virtual functions come from
- separate instances of the same class type. In the following example, there are
- two objects (instances) of class L. Because of this, there are two data members
- L:, one in class A and one in class B. If the declaration of class D is
- allowed, incrementing L: in a call to L: with a pointer to class V is
- ambiguous.
-
- class V
- {
- public:
- virtual void f();
- };
- class L : virtual public V
- {
- int count;
- void f();
- };
- void L::f() {++count;}
- class A : public L
- { /* ... */ };
- class B : public L
- { /* ... */ };
- class D : public A, public B { /* ... */ }; // error
- void main ()
- {
- D d;
- V* vptr = &d;
- vptr->f();
- }
-
- In the above example, the function L: is expecting a pointer to an L object,
- that is the this pointer for class L, as its first implicit argument. Because
- there are two objects of class L in a D object, there are two this pointers
- that could be passed to L:. Because it is not possible for the &xcomp.
- &xcompos2. to decide which this pointer to pass to L:, the declaration of class
- D is flagged as an error.
-
-
- ΓòÉΓòÉΓòÉ 13.5.2. Virtual Function Access ΓòÉΓòÉΓòÉ
-
- The access for a virtual function is specified when it is declared. The access
- rules for a virtual function are not affected by the access rules for the
- function that later overrides the virtual function. In general the access of
- the overriding member function is not known.
-
- If a virtual function is called with a pointer or reference to a class object,
- the type of the class object is not used to determine the access of the virtual
- function. Instead, the type of the pointer or reference to the class object is
- used. In the following example, when the function f() is called using a pointer
- having type B*, bptr is used to determine the access to the function f(). Even
- though the definition of f() defined in class D is executed, the access of the
- member function f() in class B is used. When the function f() is called using a
- pointer having type D*, dptr is used to determine the access to the function
- f(). This call produces an error because f() is declared private in class D.
-
- class B
- {
- public:
- virtual void f( );
- };
- class D : public B
- {
- private:
- void f( );
- };
- // .
- // .
- // .
- void main ()
- {
- D dobj;
- B *bptr = &dobj;
- D *dptr = &dobj;
- bptr->f(); // valid, virtual B::f() is public,
- // D::f() is called
- dptr->f(); // error, D::f() is private
- }
-
-
- ΓòÉΓòÉΓòÉ 13.6. Abstract Classes ΓòÉΓòÉΓòÉ
-
- An abstract class is a class that is designed to be specifically used as a base
- class. A class is called an abstract class if it contains at least one pure
- virtual function. Pure virtual functions are inherited. You can declare a
- function to be pure by using a pure specifier in the declaration of the member
- function in the class declaration. For example:
-
- class AB // abstract class
- {
- public:
- virtual void f()= 0; // pure virtual member function
- };
- class D: public AB
- {
- public:
- void f();
- };
- // .
- // .
- // .
- void main ()
- {
- D d;
- d.f() ; // calls D::f()
- AB ab; // error, cannot create an object of an
- // abstract class type
- }
-
- A function that is declared pure has no definition and cannot be executed.
- Because a pure virtual function has no implementation, any attempt to call that
- function is undefined. Such a call does not cause an error. No objects of an
- abstract class can be created, as shown in the above example.
-
- Note: Because destructors are not inherited, a virtual destructor that is
- declared pure must have a definition.
-
- Virtual member functions are inherited. If a base class contains a pure
- virtualmember function and a class derived from that base class does not
- redefine that pure virtual member function, the derived class itself is an
- abstract class. Any attempt to create an object of the derived class type
- produces an error. For example:
-
- class AB // abstract class
- {
- public:
- virtual void f()= 0; // pure virtual member function
- };
- class D2: public AB
- {
- int a,b,c;
- public:
- void g();
- };
- // .
- // .
- // .
- void main ()
- {
- D2 d;
- // error, cannot declare an object of abstract class
- D2
- }
-
- To avoid the error in the above example, provide a declaration of D2:.
-
- You cannot use an abstract class as the type of an explicit conversion, as an
- argument type, or as the return type for a function. You can declare a pointer
- or reference to an abstract class.
-
-
- ΓòÉΓòÉΓòÉ 13.7. Related Information ΓòÉΓòÉΓòÉ
-
- "Functions" on page -- Reference CPLRfunFun not found --
-
- "C++ Classes" on page -- Reference bfx1270antl not found --
-
- "Class Members and Friends" on page -- Reference q$y11a0antl not found --.
-
-
- ΓòÉΓòÉΓòÉ 14. Chapter 14. Templates ΓòÉΓòÉΓòÉ
-
- This chapter gives describes the template facility in C++. You can use
- templates to define a family of types or functions. The following topics are
- described in this chapter:
-
- o Introduction to templates
- o Template grammar
- o Class templates
- o Function templates
- o Differences between class templates and function templates.
- o Member function templates
- o Friend functions within templates.
- o Static data members within templates.
- o define and implementation pragmas
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 14.1. Introduction to Templates ΓòÉΓòÉΓòÉ
-
- A template specifies how an individual class or function can be constructed, by
- providing a blueprint description of classes or functions within the template.
- A template definition differs from an ordinary class or function definition
- mainly in the use of the template keyword, and in the use of a type argument,
- instead of a type, in one or more of the constructs used to define the class or
- function template. Individual classes or functions can then be generated simply
- by specifying the template name and by naming the type for the particular class
- or function as the type argument of the template.
-
-
- ΓòÉΓòÉΓòÉ 14.2. Template Grammar ΓòÉΓòÉΓòÉ
-
- The syntax for declaring class and function templates is:
-
- template-declaration:
- template <
- template-argument-list
- declaration
- template-argument-list:
- template-argument
- template-argument-list ,
- template-argument
- template-argument:
- type-argument
- argument-declaration
- type-argument:
- class identifier
-
- The declaration in a template-declaration must define or declare one of the
- following:
-
- o A class
- o A function. The function cannot have default arguments.
- o A static member of a template class.
-
- The identifier of a type-argument is defined to be a type-name in the scope of
- the template declaration. A template-declaration may appear as a global
- declaration only.
-
- The template-argument-list specifies the types and the constants within the
- template that must be specified when the template is instantiated.
-
- Note: Default argument expressions are not allowed for an argument-declaration
- in a template-argument.
-
- The identifier is used as a type name within the template definition to
- identify the type of any variables or objects it refers to. Given the following
- simplified class template, where L is the identifier:
-
- template<class L> class Key
- {
- L k;
- L* kptr;
- int length;
- public:
- Key(L);
- // ...
- };
-
- The following table shows what the classes Key<int>, Key<char*>, and
- Key<mytype> look like:
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé class Key<int> i; Γöé class Key<char*> c; Γöé class Key<mytype> Γöé
- Γöé Γöé Γöé m; Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé class Key<int> { Γöé class Key<char*> { Γöé class Key<mytype> Γöé
- Γöé int k; int* kptr; Γöé char* k; char** Γöé { mytype k; Γöé
- Γöé int length; public: Γöé kptr; int length; Γöé mytype* kptr; int Γöé
- Γöé Key(int); // ... Γöé public: Key(char*); Γöé length; public: Γöé
- Γöé }; Γöé // ... }; Γöé Key(mytype); // Γöé
- Γöé Γöé Γöé ... }; Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
- The above declarations create the following objects:
-
- o i of type Key<int>
- o c of type Key<char*>
- o m of type Key<mytype>
-
- It is important to note that the three classes above have different names. The
- types contained within the angle braces are not arguments to the class names
- but part of the class names themselves. Key<int> and Key<char*> are class
- names. Within the context of the above example, a class called Key (with no
- template argument list) is undefined.
-
-
- ΓòÉΓòÉΓòÉ 14.3. Class Templates ΓòÉΓòÉΓòÉ
-
- The relationship between a class template and an individual class is like the
- relationship between a class and an individual object. An individual class
- defines how a group of objects can be constructed, while a class template
- defines how a group of classes can be generated.
-
- A template definition is identical to any valid class definition that the
- template might generate, except for the following:
-
- o The class template definition is preceded by template
- <template-argument-list> where template-argument-list can include zero or
- more type-arguments and zero or more argument-declarations. The
- template-argument-list must contain at least one argument.
-
- o Types, variables, constants and objects within the class template may be
- declared with type-arguments as well as with explicit types (for example, int
- or char).
-
- o The template-argument-list may include argument-declarations (for example,int
- a or char* b), which are generally used to define constant values within the
- created class.
-
- A class template may declare a class without defining it by using an elaborated
- type specifier. For example:
-
- template <class L,class T> class key;
-
- This reserves the name as a class template name. All template declarations for
- a class template must have the same types and number of template arguments.
- Only one template declaration containing the class definition is allowed.
-
- It is important to note the distinction between the terms class template and
- template class:
-
- o A class template is a template used to generate template classes. A class
- template can be only a declaration or it can be a definition of the class.
-
- o A template class is an instance of a class template.
-
- You can instantiate the class template by declaring a template class. If the
- definitions of the member functions of the template class are not inlined, then
- you have to define them. The syntax for instantiation of a template class is:
-
- template-class-name:
- template-name <
- template-arg-list
- template-arg-list:
- template-arg
- template-arg-list , template-arg
- template-arg:
- assignment-expression
- type-name
-
- When you instantiate a template class, the template-arg-list must match the
- template-argument-list in the class template declaration.
-
- Note: When you have nested template argument lists, you must have a separating
- space between the > at the end of the inner list and the at the end of the
- outer list. Otherwise, there is an ambiguity between the output operator and
- two template list delimiters .
-
- For example:
-
- template <class L,class T> class key
- {
- // .
- // .
- // .
- };
- template <class L> class vector
- {
- // .
- // .
- // .
- };
- void main ()
- {
- class key <int, vector<int> >; // instantiate template
- }
-
- Objects and functions of individual template classes can be accessed by any of
- the techniques used to access ordinary class member objects and functions.
- Given a class template:
-
- template<class T> class vehicle
- {
- public:
- vehicle() { /* ... */ } // constructor
- ~vehicle() {}; // destructor
- T kind[16];
- T* drive();
- static void roadmap();
- // ...
- };
-
- and the declaration:
-
- vehicle<char> bicycle; // instantiates the template
-
- the constructor, the constructed object, and the member function drive() can be
- accessed with any of the following (assuming the standard header file
- <string.h> is included in the program file):
-
- ΓöîΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö¼ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÉ
- Γöé constructor Γöé vehicle<char> bicycle; // Γöé
- Γöé Γöé constructor called automat- Γöé
- Γöé Γöé ically // object bicycle Γöé
- Γöé Γöé created Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé object bicycle Γöé strcpy (bicycle.kind, "10 Γöé
- Γöé Γöé speed"); bicycle.kind[0] = Γöé
- Γöé Γöé '2'; Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé function drive() Γöé char* n = bicycle.drive(); Γöé
- Γö£ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö╝ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöñ
- Γöé function roadmap() Γöé vehicle<char>::roadmap(); Γöé
- ΓööΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓö┤ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÿ
-
-
- ΓòÉΓòÉΓòÉ 14.3.1. Declarations and Definitions ΓòÉΓòÉΓòÉ
-
- A class template must be declared before any declaration of a corresponding
- template class. A class template definition can only appear once in any single
- compilation unit. A class template must be defined before any use of a template
- class that requires the size of the class or refers to members of the class.
- In the following example, the class template key is declared before it is
- defined. The declaration of the pointer keyiptr is valid because the size of
- the class is not needed. The declaration of keyi, however, causes an error.
-
- template <class L> class key; // class template
- declared,
- // not defined yet
- //
- class key<int> *keyiptr; // declaration
- of pointer
- //
- class key<int> keyi // error, cannot
- declare keyi
- // without knowing size
- //
- template <class L> class key; // now class
- template defined
- {
- // .
- // .
- // .
- };
-
- If a template class is defined before the corresponding class template is
- defined, the &xcomp. &xcompos2. will issue an error. A class name with the
- appearance of a template class name is considered to be a template class. In
- other words, angle brackets are valid in a class name only if that class is a
- template class.
-
- The definition of a class template is not compiled until the definition of a
- template class is required. At that point, the class template definition is
- compiled using the template-arg-list of the template class to instantiate the
- template arguments. Any errors in the class definition are flagged at this
- time. If the definition of a class template is never required, it is not
- compiled. In this case, there may be errors in the definition that are not
- flagged by the &xcomp. &xcompos2.. The -qinfo option can be used to find
- possible errors in class templates that are not compiled.
-
-
- ΓòÉΓòÉΓòÉ 14.3.2. Reference and Uniqueness ΓòÉΓòÉΓòÉ
-
- A class template can only be defined once within a compilation unit, and the
- class template name cannot be declared to refer to any other template, class,
- object, function, value, or type in the same scope.
-
-
- ΓòÉΓòÉΓòÉ 14.3.3. Nontype Template Arguments ΓòÉΓòÉΓòÉ
-
- A nontype template argument provided within a template argument list is an
- expression whose value can be determined at compile time. Such arguments must
- be constant expressions, addresses of functions or objects with external
- linkage, or addresses of class members. Nontype template arguments are normally
- used to initialize a class or to specify the sizes of class members.
-
- For nontype integral arguments, the instance argument will match the
- corresponding template argument as long as the instance argument has a value
- and sign appropriate to the argument type. If the argument expression contains
- the < operator or the operator, it should be enclosed in parentheses to
- prevent the operator from being interpreted as a delimiter for template
- argument list.
-
- For nontype address arguments, the type of the instance argument must be of the
- form identifier or &identifier, and the type of the instance argument must
- match the template argument exactly, except that a function name is changed to
- a pointer to function type before matching.
-
- Theresulting valuesof nontype template arguments within a template argument
- list form part of the template class's type. If two template class names have
- the same template name and if their arguments have identical values, they are
- the same class. In the following example, a class template is defined that
- requires a nontype template int argument as well as the type argument:
-
- template<class T, int size> class myfilebuf
- {
- T* filepos;
- static int array[size];
- public:
- myfilebuf() { /* ... */}
- ~myfilebuf();
- advance(); // function defined elsewhere in program
- };
-
- In the example above, the template argument size becomes a part of the template
- class name. An object of such a template class is created with both the type
- arguments of the class and the values of any additional template arguments.
-
- An object x, and its corresponding template class with arguments double and
- size=200, can be created from this template with a value as its second template
- argument:
-
- myfilebuf<double,200> x;
-
- x can also be created using an arithmetic expression:
-
- myfilebuf<double,10*20> x;
-
- The objects created by these expressions are identical because the template
- arguments evaluate identically. The value 200 in the first expression above
- could have been represented by an expression whose result at compile time is
- known to be equal to 200, as shown in the second construction. Note that
- arguments that contain the < operator or the > operator must be enclosed in
- parentheses to prevent the operator from being parsed as the template argument
- list delimiter when it is being used as a relational operator. For example, the
- arguments in the following definition are valid:
-
- myfilebuf<double, (20>10)> x; // valid
-
- This definition,however, is not valid because the "greater than" operator is
- interpreted as the closing delimiter of the template argument list:
-
- myfilebuf<double, 20>10> x; // error
-
- If the template arguments do not evaluate identically, the objects created are
- of different types:
-
- myfilebuf<double,200> x; // create object
- x of class
- // myfilebuf<double,200>
- myfilebuf<double,200.0> y; // error, 200.0 is a
- double,
- // not an int
-
- The instantiation of y fails because the value 200.0 is of type double and the
- template argument is of type int.
-
- The following two objects:
-
- myfilebuf<double, 128> x
- myfilebuf<double, 512> y
-
- belong to separate template classes, and referencing either of these objects
- later with myfilebuf<double> is an error.
-
- A class template does not need to have a type argument if it has nontype
- arguments. For example, the following template is a valid class template:
-
- template<int i> class C
- {
- public:
- int k;
- C() { k = i;}
- };
-
- This class template can be instantiated by declarations such as:
-
- class C<100>;
- class C<200>;
-
- Again, these two declarations refer to distinct classes because the values of
- their nontype arguments differ.
-
-
- ΓòÉΓòÉΓòÉ 14.3.4. Explicitly Defined Template Classes ΓòÉΓòÉΓòÉ
-
- You can override the definition of a class template of a particular template
- class by providing a class definition for the type of class required. For
- example, the following class template will create a class for each type for
- which it is referenced, but that class may be inappropriate for a particular
- type:
-
- template<class M> class portfolio
- {
- double capital;
- M arr;
- // ...
- } ;
-
- The type for which the template class is inappropriate can be defined by using
- the applicable template class name. Assuming the inappropriately defined type
- was stocks, you could redefine the class portfolio<stocks> as follows:
-
- class portfolio<stocks>
- {
- double capital;
- stocks yield;
- // ...
- };
-
- This explicit definition must be seen before the template class is referenced.
-
-
- ΓòÉΓòÉΓòÉ 14.4. Function Templates ΓòÉΓòÉΓòÉ
-
- A function template allows you to define a group of functions that are the same
- except for the types of one or more of their arguments or objects. All type
- arguments in a function template must be used in the argument list or in the
- class qualifier for the function name. The type of a template function argument
- need not be explicitly specified when the template function is called. In this
- respect, a template function differs from a template class.
-
-
- ΓòÉΓòÉΓòÉ 14.4.1. Example of a Function Template ΓòÉΓòÉΓòÉ
-
- If you want to create a function approximate() which determines whether two
- values are within 5% of each other, you can define the following template:
-
- #include<math.h>
- template <class T> int approximate (T first, T
- second)
- {
- double aptemp=double(first)/double(second);
- return int(abs(aptemp-1.0) <= .05);
- };
-
- Assuming you have two values of type float you want to compare, you can use the
- approximate function template:
-
- float a=3.24, b=3.35;
- if (approximate(a,b))
- cout << "a and b are pretty close" <<
- endl;
-
- A template function int approximate(float,float) is generated to resolve the
- call.
-
- Note: It is important to note the distinction between the terms function
- template and template function:
-
- o Function template is a template used to generate template functions. A
- function template can be only a declaration or it can define the function.
-
- o Template function is a function generated by a function template.
-
-
- ΓòÉΓòÉΓòÉ 14.4.2. Overloading Resolution for Template Functions ΓòÉΓòÉΓòÉ
-
- When a function is invoked with overloaded arguments, overloading resolution is
- done in the following order:
-
- 1. Look for a function with an exact type match. This does not include
- template functions, unless such functions were explicitly declared using a
- function declaration. Trivial conversions are performed if they produce an
- exact type match.
-
- 2. Look for a function template that allows generation of a function with an
- exact type match. Trivial conversions are performed if they produce an
- exact type match.
-
- 3. Try ordinary overloading resolution for functions already present. This
- does not include template functions, unless such functions were explicitly
- declared using a function declaration.
-
- A call to a template function causes an error and no overloading is done if the
- following conditions are true:
-
- o The only available functions for a call are template functions
-
- o These functions would require nontrivial conversions for the call to succeed
-
- o These functions have not been explicitly declared.
-
- In the case of the approximate() function template above, if the two input
- values are of different types, overloading resolution will not take place:
-
- float a=3.24;
- double b=3.35;
- if (approximate(a,b)) // error, different types
- { /* ... */ }
-
- The solution is to force a conversion to one of the available function types by
- explicitly declaring the function for the chosen type. To resolve the
- float/double example above, include the following function declaration:
-
- int approximate(double a, double b);
- // force conversion of the float to double
-
- This declaration creates a function approximate() which expects two arguments
- of type double, so that when approximate(a,b) is called, the overloading is
- resolved by converting variable a to type double.
-
- For further details on argument matching and conversions, see "Trivial
- Conversions" , "Type Conversions" , and "Integral Promotions"
-
-
- ΓòÉΓòÉΓòÉ 14.4.3. Defining Template Functions ΓòÉΓòÉΓòÉ
-
- Because template functions may be generated in all compilation units that
- contain function template definitions, you may want to group function template
- definitions into one or two compilation units.
-
-
- ΓòÉΓòÉΓòÉ 14.4.4. Explicitly Defined Template Functions ΓòÉΓòÉΓòÉ
-
- In some situations a function template may define a group of functions in
- which, for one function type, the function definition would be inappropriate.
- For instance, the function template:
-
- template<class T> int approximate(T first, T second);
-
- defined "Example of a Function Template" ) , determines whether two values are
- within 5% of each other. The algorithm used for this function template is
- appropriate for numerical values, but for char* values, it would indicate
- whether the pointers to two character strings are within 5% of one another, not
- whether the strings themselves are approximately equal. Whether two pointers
- are within 5% of each other is not useful information. You can define an
- explicit template function for char* values to compare the two strings
- themselves, character by character. The following explicitly defined template
- function compares two strings and returns a value indicating whether or not
- more than 5% of the characters differ between the two strings:
-
- #include<string.h>
- int approximate(char *first, char *second)
- {
- if (strcmp(first,second) == 0)
- return 1; // strings are identical
- double difct=0;
- int maxlen=0;
- if (strlen(first)>strlen(second))
- maxlen=strlen(first);
- else maxlen=strlen(second);
- for (int i=0; i<=maxlen ; ++i)
- if ( first[i] != second[i] )
- difct++;
- return int((difct / maxlen) <= .05 );
- }
-
- Given this definition, the function call:
-
- approximate("String A","String B");
-
- invokes the explicitly defined function above, and no template function will be
- generated.
-
- Explicit definition has the same effect on template overloading resolution as
- explicit declaration (see "Overloading Resolution for Template Functions" ). If
- a template function is explicitly defined for:
-
- int approximate(double a, double b) { /* ... */ }
-
- then a call of:
-
- double a=3.54;
- float b=3.5;
- approximate(a,b);
-
- resolves in a call to approximate(double a, double b), and variable b is
- converted to type double.
-
-
- ΓòÉΓòÉΓòÉ 14.4.5. Declarations and Definitions ΓòÉΓòÉΓòÉ
-
- When a template function is defined explicitly within a compilation unit, this
- definition is used in preference to any instantiation from the function
- template. For example, if one compilation unit contains the code:
-
- #include<iostream.h>
- template <class T> T f(T i) {return i+1;}
- void main()
- {
- cout << f(2) << endl;
- }
-
- and another contains:
-
- int f(int i) {return i+2;}
-
- when compiled and run, the program prints the number 4 to standard output,
- indicating that the explicitly defined function was used to resolve the call to
- f().
-
- Each template, whether of a class or of a function, must be defined at most
- once within a compilation unit. The same applies to an explicitly defined
- template class or function. Function templates and class templates may be
- declared many times.
-
- A template class is considered declared if its name is used. A template
- function is considered declared if any of the following applies:
-
- o A function whose name matches a function template's name is declared, and an
- appropriate template function can be generated.
-
- o A function whose name matches a function template's name is called, and an
- appropriate template function can be generated.
-
- o A function whose name matches a function template's name is called, and the
- template function has been explicitly defined.
-
- o The address of a template function is taken in such a way that instantiation
- can occur. This means the pointer to function must supply a return type and
- argument types that can be used to instantiate the template function.
-
- A template function is instantiated or generated if the function is referenced
- in any of the following ways, provided that function is not explicitly defined
- elsewhere in the program:
-
- o The function is declared
- o A call to the function is made
- o The address of the function is taken.
-
- When a template function is instantiated, the body of the function template is
- compiled using the template-arg-list of the template class to instantiate the
- template arguments. Any errors in the function definition are flagged at this
- time. If a template function is never generated from a function template, it is
- not compiled. In this case, there may be errors in the function definition that
- are not flagged by the &xcomp. &xcompos2..
-
-
- ΓòÉΓòÉΓòÉ 14.5. Differences Between Class and Function Templates ΓòÉΓòÉΓòÉ
-
- The name of a template class is a compound name consisting of the template name
- and the full template argument list enclosed in angle braces. Any references
- to a template class must use this complete name. For example:
-
- template <class T, int range> class ex
- {
- T a;
- int r;
- // ...
- };
- //...
- ex<double,20> obj1; // valid
- ex<double> obj2; // error
- ex obj3; // error
-
- C++ requires this explicit naming convention to ensure that the appropriate
- class can be generated.
-
- A template function, on the other hand, has the name of its function template
- and the particular function chosen to resolve a given template function call is
- determined by the type of the calling arguments. In the following example, the
- call min(a,b) is effectively a call to min(int a, int b), and the call min(af,
- bf) is effectively a call to min(float a, float b):
-
- template<class T> T min(T a, T b)
- {
- if (a < b)
- return a;
- else
- return b;
- }
- void main()
- {
- int a = 0;
- int b = 2;
- float af = 3.1;
- float bf = 2.9;
- cout << "Here is the smaller int " <<
- min(a,b) << endl;
- cout << "Here is the smaller float " <<
- min(af, bf) << endl;
- }
-
-
- ΓòÉΓòÉΓòÉ 14.6. Member Function Templates ΓòÉΓòÉΓòÉ
-
- In "Function Templates" a function template was defined outside of any template
- class. However, functions in C++ are often member functions of a class. If you
- want to create a class template and a set of function templates to go with that
- class template, you do not have to create the function templates explicitly, as
- long as the function definitions are contained within the class template. Any
- member function (inlined or noninlined) declared within a class template is
- implicitly a function template. When a template class is declared, it
- implicitly generates template functions for each function defined in the class
- template.
-
- There are three ways to define template member functions:
-
- o Explicitly at file scope for each type used to instantiate the template
- class. For example:
-
- template <class T> class key
- {
- public:
- void f(T);
- };
- void key<char>::f(char) { /* ... */ }
- void key<int>::f(int ) { /* ... */ }
-
- void main()
- {
- int i = 9;
- key< int> keyobj;
- keyobj.f(i);
- }
-
- o At file scope with the template-arguments. For example:
-
- template <class T> class key
- {
- public:
- void f(T);
- };
- template <class T> void key <T>::f(T) { /* ... */
- }
-
- void main()
- {
- int i = 9;
- key< int> keyobj;
- keyobj.f(i);
- }
-
- o Inlined in the class template itself. For example:
-
- template <class T> class key
- {
- public:
- void f(T) { /* ... */ }
- };
-
- void main()
- {
- int i = 9;
- key< int> keyobj;
- keyobj.f(i);
- }
-
- Member function templates are used to instantiate any functions that are not
- explicitly generated. If you have both a member function template and an
- explicit definition, the explicit definition is used.
-
- The template argument is not used in a constructor name. For example,
-
- template<class L> class Key
- {
- Key(); // default constructor
- Key( L ); // constructor taking L by value
- Key<L>( L ); // error, <L> implicit within
- class template
- };
-
- The declaration Key<L>(L) is an error because the constructor does not use the
- template argument. Assuming the above class template was corrected by removing
- the offending line, you can define a function template for the class template's
- constructor:
-
- // Constructor contained in function template:
- template<class L>
- Key<L>::Key(int) { /* ... */ }
- // valid, constructor template argument assumed
- template<class L>
- Key<L>::Key<L>(int) { /* ... */ }
- /* error, constructor template argument <L> implicit
- in
- class template argument */
-
- A template function name does not include the template argument. The template
- argument does, however, appear in the template class name if a member function
- of a template class is defined or declared outside of the class template. The
- definition:
-
- Key<L>::Key(int) { /* ... */ }
-
- is valid because Key<L> (with template argument) refers to the class, while
- Key(int) { /* ... */ } refers to the member function.
-
-
- ΓòÉΓòÉΓòÉ 14.7. Friends ΓòÉΓòÉΓòÉ
-
- A friend function can be declared in a class template either as a single
- function shared by all classes created by the template or as a template
- function that varies from class to class within the class template. For
- example:
-
- template<class T> class portfolio
- {
- //...
- friend void taxes();
- friend void transact(T);
- friend portfolio<T>* invest(portfolio<T>*);
- friend portfolio* divest(portfolio*); //error
- // ...
- };
-
- In this example, each declaration has the following characteristics:
-
- o taxes( ) is single function that can access private and protected members of
- any template class generated by the class template. Note that taxes() is not
- a template function.
-
- o transact(T) is a function template which declares a distinct function for
- each class generated by the class template. The only private and protected
- members that can be accessed by functions generated from this template are
- the private and protected members of their template class.
-
- o invest(portfolio<T>*) is a function template whose return and argument types
- are pointers to objects of type portfolio<T>. Each class generated by the
- class template will have a friend function of this name, and each such
- function will have a pointer to an object of its own class as both its return
- type and its argument type.
-
- o divest(portfolio*) is an error because portfolio* attempts to point to a
- class template. A pointer to a class template is undefined and produces an
- error. This statement can be corrected by using the syntax of the invest()
- function template instead.
-
- Because all friend functions in this example are declared but not defined, you
- could create a set of function templates to define those functions that are
- implicitly template functions (that is, all the valid functions except
- taxes()). The function templates would then be used to instantiate the template
- functions as required.
-
-
- ΓòÉΓòÉΓòÉ 14.8. Static Data Members ΓòÉΓòÉΓòÉ
-
- A static declaration within a class template declares a static data member for
- each template class generated from the template. The static declaration may be
- of type template-argument or of any defined type.
-
- Like member function templates, you can explicitly define a static data member
- of a template class at file scope for each type used to instantiate a template
- class, for example:
-
- template <class T> class key
- {
- public:
- static T x;
- };
- int key<int>::x;
- char key<char>::x;
- void main()
- {
- key<int>::x = 0;
- }
-
- You can also define a static data member of a template class using a template
- definition at file scope, for example:
-
- template <class T> class key
- {
- public:
- static T x;
- };
- template <class T> T key<T> ::x; // template definition
- void main()
- {
- key<int>::x = 0;
- }
-
- When you instantiate a template class, you must have either an explicit
- definition or a template definition for each static data member. If you have
- both, the explicit definition is used.
-
- In the following example:
-
- template<class L> class Key
- {
- static L k;
- static L* kptr;
- static int length;
- // ...
- }
-
- the definitions of static variables and objects must be instantiated at file
- scope. If the classes Key<int> and Key<double> are instantiated from the above
- template, and no template definitions exist, the following static data members
- must be explicitly defined at file scope, or an error occurs:
-
- int Key<int>::k, Key<int>::length, Key<double>::length;
- int* Key<int>::kptr;
- double Key<double>::k;
- double* Key<double>::kptr = 0;
-
-
- ΓòÉΓòÉΓòÉ 14.9. define and implementation Pragmas ΓòÉΓòÉΓòÉ
-
- The define pragma can be used to force the definition of a template class
- without actually defining an object of the class. The syntax is:
-
- pragma-define:
- #pragma define (template-class-name)
-
- The implementation pragma is used to tell the compiler the name of the file
- that contains the function template definitions corresponding to the template
- declarations in the include file containing the pragma. The syntax is:
-
- pragma-implementation:
- #pragma implementation
- (string-literal)
-
- The pragmas can appear anywhere that a declaration is allowed.
-
- The define and implementation pragmas are used when organizing your program
- for the efficient or automatic generation of template functions.
-
-
- ΓòÉΓòÉΓòÉ 14.10. Related Information ΓòÉΓòÉΓòÉ
-
- "Functions"
-
- "C++ Classes"
-
-
- ΓòÉΓòÉΓòÉ 15. Chapter 15. Exception Handling ΓòÉΓòÉΓòÉ
-
- This chapter describes the C++ implementation of exception handling and
- discusses the following topics:
-
- o Introduction to C[++] exception handling
- o Formal and Informal Exception Handling
- o Exception handling grammar
- o Transferring control
- o Constructors and destructors
- o Exception specifications
- o Special functions.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 15.1. Introduction to C++ Exception Handling ΓòÉΓòÉΓòÉ
-
- Exception handling provides a way for a function that encounters an unusual
- situation to throw an exception and pass control to a direct or indirect caller
- of that function. The caller may or may not be able to handle the exception.
- Code that intercepts an exception is called a handler. Regardless of whether or
- not the caller can handle an exception, it may rethrow the exception so it can
- be intercepted by another handler.
-
- C++ provides three language constructs to implement exception handling:
-
- o Try blocks
- o Catch blocks
- o Throw expressions.
-
- Within a function, any unusual situation can be flagged with a throw
- expression. You can throw an object in order to pass information back to the
- caller. Any object can be thrown, including the object that caused the
- exception or an object constructed when the exception occurred.
-
- A call to a function that may throw an exception should be enclosed within a
- try statement. If the called function throws an exception and an exception
- handler is defined to catch the type of the object thrown, the exception
- handler is executed. In C++, a catch block implements an exception handler.
-
- A catch block follows immediately after a try statement or immediately after
- another catch block. A catch block includes a parenthesized exception
- declaration containing optional qualifiers, a type, and an optional variable
- name. The declaration specifies the type of object that the exception handler
- may catch. Once an exception is caught, the body of the catch block is
- executed. If a function throws an exception that cannot be caught, the program
- is terminated.
-
- Exception handling is not strictly synonymous with error handling, because the
- implementation allows the passing of an exception whether or not an error
- actually occurred. You can use exception handlers for things other than
- handling errors.
-
-
- ΓòÉΓòÉΓòÉ 15.2. Formal and Informal Exception Handling ΓòÉΓòÉΓòÉ
-
- While the exception handling features of C++ offer a formal mechanism for
- handling exceptions (language implemented), in many situations informal
- exception handling (logic implemented) is more appropriate. Generally speaking,
- formal exception handling should be implemented in libraries, classes, and
- functions likely to be accessed by several programs or programmers and in
- classes and functions that are repeatedly accessed within a program but are not
- well-suited to handling their exceptions themselves. Since formal exception
- handling is designed for exceptional circumstances, exception handling is not
- guaranteed to be efficient. When you do not invoke exception handling, overhead
- is minimal.
-
- Informal exception handling, in which the user defines the appropriate action
- if an error or exception occurs, is often more suitable for handling errors.
- For example, a simple error, such as a user entering an incorrect input, can
- more easily and clearly be handled by testing the input for validity and by
- requesting the input again if the original input is incorrect.
-
-
- ΓòÉΓòÉΓòÉ 15.3. Exception Handling Grammar ΓòÉΓòÉΓòÉ
-
- The three keywords designed for exception handling in C++ are try, throw, and
- catch. The syntax is:
-
- try block:
- try compound-statement
- handler-list
- handler-list:
- handler [handler-list]
- handler:
- catch (
- exception-declaration )
- compound-statement
- exception-declaration:
- type-specifier-list declarator
- type-specifier-list abstract-declarator
- type-specifier-list
- ...
- throw-expression:
- throw
- [assignment-expression]
-
- The steps required to implement an exception handler are:
-
- 1. Functions that are expected to be used by many programs are coded so that,
- when an error is detected, an exception is thrown. The throw expression
- generally throws an object. It may be created explicitly for purposes of
- exception handling, or it may be the object that caused the error to be
- detected.
-
- 2. Exceptions are anticipated in a caller by use of a try statement. Function
- calls that you anticipate might produce an exception can be enclosed in
- braces and preceded by the keyword try.
-
- 3. Immediately following the try block, you can code one or more catch blocks.
- Each catch block identifies what type or class of objects it is capable of
- catching. If the object thrown matches the type of a catch expression,
- control passes to that catch block. If the object thrown does not match the
- first catch block, subsequent catch blocks are searched for a matching
- type. If no match is found, the search continues in all enclosing try
- blocks and then in the caller of the current function. If no match is found
- after all try blocks are searched, a call to terminate() is made, and the
- program is terminated normally. (For details on the default handlers of
- uncaught exceptions, see "terminate()"
-
- 1. Any object can be thrown if it can be copied and destroyed in the function
- from which the throw occurs.
-
- 2. Exceptions should never be thrown from a signal handler. The result is
- undefined, and can cause program termination.
-
- A catch argument is illegal if it is a value argument and it is not possible to
- generate a copy of it. For example:
-
- class B {
- public:
- B();
- B(B&);
- };
- // the following catch block will cause an error
- //
- catch(const B x)
- {
- // .
- // .
- // .
- }
-
- The catch block causes an error because the &xcomp. &xcompos2. does not know
- the type of the object thrown at compile time. It assumes that the type of the
- thrown object is the same as the type of the catch argument. In the above
- example, the thrown object is assumed to be of type const B. The compiler uses
- a copy constructor on the thrown argument to create the catch argument. Since
- there is no copy constructor for class B that accepts const B as an input
- argument, the compiler is not able to perform the construction and an error
- occurs. Similarly, a throw expression causes an error if it is not possible to
- generate a copy of the value of the expression being thrown.
-
-
- ΓòÉΓòÉΓòÉ 15.4. Transferring Control ΓòÉΓòÉΓòÉ
-
- C++ implements the termination model of exception handling. In the termination
- model, when an exception is thrown, control never returns to the throw point.
- The throw point is the point in program execution where the exception occurred.
-
- C++ exception handling does not implement the resumption model of exception
- handling which allows an exception handler to correct the exception and then
- return to the throw point.
-
- When an exception is thrown, control is passed out of the throw expression, and
- out of the try block that anticipated the exception. Control is passed to the
- catch block whose exception type matches the object thrown. The catch block
- handles the exception as appropriate. If the catch block ends normally, the
- flow of control passes over all subsequent catch blocks.
-
- When an exception is not thrown from within a try block, the flow of control
- continues normally through the block, and passes over all catch blocks
- following the try block.
-
- An exception handler cannot return control to the source of the error by using
- the return statement. A return issued in this context returns from the function
- containing the catch block.
-
- If an exception is thrown and no try block is active, or if a try block is
- active and no catch block exception declaration matches the object thrown, a
- call to terminate() is issued.
-
- A call to terminate() in turn calls abort() to terminate the program. abort()
- is defined in the standard header file <stdlib.h terminate(), see "Special
- Functions"
-
- The following example illustrates the basic use of try, catch, and throw. The
- program prompts for a numerical user input and determines the input's
- reciprocal. Before it attempts to print the reciprocal to standard output, it
- checks that the input value is nonzero, to avoid a division by zero. If the
- input is zero, an exception is thrown, and the catch block catches the
- exception. If the input is nonzero, the reciprocal is printed to standard
- output.
-
- #include <iostream.h>
- #include <stdlib.h>
- class IsZero { /* ... */ };
- void ZeroCheck( int i )
- {
- if (i==0)
- throw IsZero();
- }
- void main()
- {
- double a;
- cout << "Enter a number: ";
- cin >> a;
- try
- {
- ZeroCheck( a );
- cout << "Reciprocal is " <<
- 1.0/a << endl;
- }
- catch ( IsZero )
- {
- cout << "Zero input is not valid"
- << endl;
- exit(1);
- }
- exit(0);
- }
-
- This example could have been coded more efficiently by using informal exception
- handling. However, it provides a simple illustration of formal exception
- handling.
-
-
- ΓòÉΓòÉΓòÉ 15.4.1. Catching Exceptions ΓòÉΓòÉΓòÉ
-
- You can declare a handler to catch many types of exceptions. The allowable
- objects that a function can catch are declared in an exception-declaration. You
- can catch objects of the fundamental types, base and derived class objects,
- references and pointers to all of these types. You can also catch const and
- volatile types.
-
- You can also use the catch(...) form of the handler to catch all thrown
- exceptions that have not been caught by a previous catch block. The ellipsis in
- the exception-declaration indicates that any exception thrown can be handled by
- this handler.
-
- If an exception is caught by a catch(...) block, there is no direct way to
- access the object thrown. Information about an exception caught by catch(...)
- is very limited.
-
- You can declare an optional variable name if you want to access the thrown
- object in the catch block.
-
- A catch block can only catch accessible objects. The object caught must have an
- accessible copy constructor. For more details on access, see "Member Access"
- For further details on copy constructors, see "Copy by Initialization"
-
-
- ΓòÉΓòÉΓòÉ 15.4.2. Order of Catching ΓòÉΓòÉΓòÉ
-
- Always place a catch block that catches a derived class before a catch block
- that catches the base class of that derived class (following a try block). If a
- catch block for objects of a base class is followed by a catch block for
- objects of a derived class of that base class, the latter block is flagged as
- an error.
-
- A catch block of the form catch(...) must be the last catch block following a
- try block. This ensures that the catch(...) block does not prevent more
- specific catch blocks from catching exceptions intended for them. If a
- catch(...) block is provided after a try block, it must be the last catch block
- or an error occurs.
-
-
- ΓòÉΓòÉΓòÉ 15.4.3. Matching Between Exceptions Thrown and Caught ΓòÉΓòÉΓòÉ
-
- An argument in the exception-declaration of a handler (catch argument) will
- match an argument in the expression of the throw expression (throw argument) if
- any of the following conditions is met:
-
- o The catch argument type matches the type of the thrown object.
-
- o The catch argument is a public base class of the thrown class object.
-
- o The catch specifies a pointer type, and the thrown object is a pointer type
- that can be converted to the pointer type of the catch argument by standard
- pointer conversion.
-
- Note: If the type of the thrown object is const or volatile the catch argument
- must also be a const or volatile for a match to occur. However, a const,
- volatile, or reference type catch argument can match a nonconstant,
- nonvolatile, or nonreference object type. A non-reference catch argument type
- will match a reference to an object of the same type.
-
-
- ΓòÉΓòÉΓòÉ 15.4.4. Nested try Blocks ΓòÉΓòÉΓòÉ
-
- When try blocks are nested and a throw occurs in a function called by an inner
- try block, control is transferred outwards through the nested try blocks until
- the first catch block is found whose argument matches the argument of the throw
- expression. For example:
-
- try
- {
- func1();
- try
- {
- func2();
- }
- catch (spec_err) { /* ... */ }
- func3();
- }
- catch (type_err) { /* ... */ }
- // if no throw is issued, control resumes here.
-
- In the above example, if spec_err is thrown within the inner try block (in this
- case, from func2() ), the exception is caught by the inner catch block, and,
- assuming this catch block does not transfer control, func3() is called. If
- spec_err is thrown after the inner try block (for instance, by func3() ), it is
- not caught and the function terminate() is called. If the entire try block in
- the example is in a function that has a throw list and does not include
- spec_err on its throw list, unexpected() is called. If the exception thrown
- from func2() in the inner try block is type_err, the program will skip out of
- both try blocks to the second catch block without invoking func3(), because no
- appropriate catch block exists following the inner try block.
-
- It is also possible to nest a try block within a catch block.
-
-
- ΓòÉΓòÉΓòÉ 15.4.5. Rethrowing an Exception ΓòÉΓòÉΓòÉ
-
- If a catch block cannot handle the particular exception it has caught, you can
- rethrow the exception. The rethrow expression (throw; with no argument) causes
- the originally thrown object to be rethrown.
-
- Because the exception has already been caught at the scope in which the rethrow
- expression occurs, it is rethrown out to the next dynamically enclosing try
- block. Therefore, it cannot be handled by catch blocks at the scope in which
- the rethrow expression occurred. Any catch blocks following the dynamically
- enclosing try block have an opportunity to catch the exception.
-
- In the following example, catch(FileIO) catches any object of type FileIO and
- any objects that are public base classes of the FileIO class. It then checks
- for those exceptions it can handle. For any exception it cannot handle, it
- issues a rethrow expression to rethrow the exception and allow another handler
- in a dynamically enclosing try block to handle the exception.
-
- #include <iostream.h>
- class FileIO
- {
- public:
- int notfound;
- int endfile;
- FileIO(); // initialize data members
- // the following member functions throw an exception
- // if an input error occurs
- void advance(int x);
- void clear();
- void put(int x, int y);
- };
- // .
- // .
- // .
- void f()
- {
- FileIO fio;
- try
- {
- // call member functions of FileIO class
- fio.advance (1);
- fio.clear();
- fio.put(1,-1);
- }
-
- catch(FileIO fexc)
- {
- if (fexc.notfound)
- cout << "File not Found" <<
- endl;
- else if (fexc.endfile)
- cout << "End of File" <<
- endl;
- else
- throw; // rethrow to outer handler
- }
- catch(...) { /* ... */ } // catch other
- exceptions
- }
- main()
- {
- try
- {
- f();
- }
- catch(FileIO) { cout << "Outer Handler" <<
- endl;}
- }
-
- The rethrow expression can be caught by any catch(...) whose argument matches
- the argument of the exception originally thrown. Note that, in this example,
- the catch(...) will not catch the rethrow expression because, when the rethrow
- expression is issued, control passes out of the scope of the function f() into
- the next dynamically enclosing block.
-
-
- ΓòÉΓòÉΓòÉ 15.4.6. Using a Conditional Expression in a Throw Expression ΓòÉΓòÉΓòÉ
-
- You can use a conditional expression as a throw expression. Consider the
- following example:
-
- #include <iostream.h>
- void main() {
- int doit = 1;
- int dont = 0;
- float f = 8.9;
- int i = 7;
- int j = 6;
- try { throw doit ? i : f; }
- catch (int x)
- {
- cout << "Caught int " << x <<
- endl;
- }
- catch (float x)
- {
- cout << "Caught float " << x
- << endl;
- }
- catch (double x)
- {
- cout << "Caught double " << x
- << endl;
- }
- catch (...)
- {
- cout << "Caught something " <<
- endl;
- }
- }
-
- This example produces the following output:
-
- Caught float 7
-
- At first glance, it looks as if the block that catches integer values should do
- the catch, but i is converted to a float value in the try block because it is
- in a conditional expression with the float value f. If the try block in the
- example is replaced with the following try block:
-
- try { throw doit ? i : j; }
-
- The following output is produced:
-
- Caught int 7
-
-
- ΓòÉΓòÉΓòÉ 15.5. Constructors and Destructors ΓòÉΓòÉΓòÉ
-
- When an exception is thrown and control passes to a catch block following a try
- block, destructors are called for all objects constructed since the beginning
- of the try block directly associated with that catch block. If an exception is
- thrown during construction of an object consisting of subobjects or array
- elements, destructors will only be called for those subobjects or array
- elements successfully constructed before the exception was thrown.
-
- For more information on constructors and destructors, see "Constructors and
- Destructors"
-
- If a destructor detects an exception and issues a throw, the exception can be
- caught if the caller of the destructor was contained within a try block and an
- appropriate catch is coded.
-
- If an exception is thrown by a function called from an inner try block, but
- caught by an outer try block (because the inner try block did not have an
- appropriate handler), all objects constructed within both the outer and all
- inner try blocks are destroyed. If the thrown object has a destructor, the
- destructor is not called until the exception is caught and handled.
-
- Because a throw expression throws an object and a catch statement can catch an
- object, the object thrown enables error-related information to be transferred
- from the point at which an exception is detected to the exception's handler. If
- you throw an object with a constructor, you can construct an object that
- contains information relevant to the catch expression. In the following
- example, an object of class DivideByZero is thrown by the function divide().
- The constructor copies the string "Division by zero" into the char array
- errname. Since DivideByZero is a derived class of class Matherr, the catch
- block for Matherr catches the thrown exception. The catch block can then access
- information provided by the thrown object, in this case the text of an error
- message.
-
- #include<string.h> // needed for strcpy
- #include<iostream.h>
- class Matherr { public: char errname[30]; };
- class DivideByZero : public Matherr
- {
- public:
- DivideByZero() {strcpy (errname, "Division by
- zero");}
- };
- double divide(double a, double b)
- {
- if (b == 0) throw DivideByZero();
- return a/b;
- }
-
- void main()
- {
- double a=7,b=0;
- try {divide (a,b);}
- catch (Matherr xx)
- {
- cout << xx.errname << endl;
- }
- }
-
- Exception handling can be used in conjunction with constructors and destructors
- to provide resource management that ensures that all locked resources are
- unlocked when an exception is thrown. Consider the following example:
-
- class data
- {
- public:
- void lock(); // prevent other users
- from
- // changing the object
- void unlock(); // allow other users to change
- // the object
- };
- void q(data&), bar(data&);
- // .
- // .
- // .
- main()
- {
- data important;
- important.lock();
- q(important);
- bar(important);
- important.unlock();
- }
-
- If q() or bar() throw an exception, important.unlock() will not be called and
- the data will stay locked. This problem can be corrected by using a helper
- class to write an "exception aware" program for resource management.
-
- class data
- {
- public:
- void lock(); // prevent other users from
- // changing the object
- void unlock(); // allow other users to change
- // the object
- };
- class locked_data // helper class
- {
- data& real_data;
- public:
- locked_data(data& d) : real_data(d)
- {real_data.lock();}
- ~locked_data() {real_data.unlock();}
- };
- void q(data&), bar(data&);
- // .
- // .
- // .
- main()
- {
- data important;
- locked_data my_lock(important);
- q(important);
- bar(important);
- }
-
- In this case if q() or bar() throws an exception, the destructor for my_lock
- will be called, and the data will be unlocked.
-
-
- ΓòÉΓòÉΓòÉ 15.6. Exception Specifications ΓòÉΓòÉΓòÉ
-
- C++ provides a mechanism to ensure that a given function is limited to throwing
- only a specified list of exceptions. An exception specification at the
- beginning of any function acts as a guarantee to the function's caller that the
- function will not throw any exception not contained in the exception
- specification. For example, a function:
-
- void translate() throw(unknown_word,bad_grammar) { /* ...
- */ }
-
- explicitly states that it will not throw any exception other than unknown_word
- or bad_grammar. translate() must handle any exceptions thrown by functions it
- might call, unless those exceptions are specified in the exception
- specification of translate(). If an exception is thrown by a function called by
- translate() and the exception is not handled by translate() or contained in the
- exception specification of translate(), unexpected() is called.
-
-
- ΓòÉΓòÉΓòÉ 15.6.1. Exception Specification Grammar ΓòÉΓòÉΓòÉ
-
- The syntax of theexception specification is:
-
- exception-specification:
- throw (
- [type-list]
- )
- type-list:
- type-name
- type-list , type-name
-
- For further details on type-name, see "Type Names"
-
- If an exception is thrown from a function that has not specified the thrown
- exception in its exception specification, a call of the function unexpected(),
- which is discussed in the following section "Special Functions", will result.
-
-
- ΓòÉΓòÉΓòÉ 15.6.2. Empty Exception Specifications ΓòÉΓòÉΓòÉ
-
- A function with an empty throw() specification guarantees that the function
- will not throw any exceptions.
-
-
- ΓòÉΓòÉΓòÉ 15.6.3. Functions Without an Exception Specification ΓòÉΓòÉΓòÉ
-
- A function without an exception specification allows any object to be thrown
- from the function.
-
-
- ΓòÉΓòÉΓòÉ 15.6.4. Other Exception Specifications ΓòÉΓòÉΓòÉ
-
- The compiler does not prevent an exception specification from defining a more
- limited set of valid exceptions than the set of exceptions the function may
- actually throw. Such an error will be detected only at run time, and only if
- the unspecified exception is thrown.
-
- In the following example, NameTooShort is thrown from within a function that
- explicitly states that it will only throw NameTooLong. This is a valid
- function, although at run time, if NameTooShort is thrown, a call to
- unexpected() will be made.
-
- #include <string.h> // needed for strlen
- class NameTooLong {};
- class NameTooShort {};
- void check(char* fname) throw (NameTooLong)
- {
- if ( strlen(fname)<4 ) throw NameTooShort();
- }
-
- If a function with an exception specification calls a subfunction with a less
- restrictive exception specification (an exception specification that contains
- more objects than the calling function's exception specification), any thrown
- objects from within the subfunction that are not handled by the subfunction and
- that are not part of the outer function's specification list must be handled
- within the outer function. If the outer function fails to handle an exception
- not in its exception specification, a call to unexpected() is made.
-
-
- ΓòÉΓòÉΓòÉ 15.7. Special Functions ΓòÉΓòÉΓòÉ
-
- Not all thrown errors can be caught and successfully dealt with by a catch
- block. There are situations where the most sensible way to handle an exception
- is to terminate the program. Two special library functions are implemented in
- C++ to process exceptions not properly handled by catch blocks, or exceptions
- thrown outside of a valid try block. These functions are unexpected() and
- terminate().
-
-
- ΓòÉΓòÉΓòÉ 15.7.1. unexpected() ΓòÉΓòÉΓòÉ
-
- When a function with an exception specification throws an exception that is not
- listed in its exception specification, the function unexpected() is called. The
- function unexpected() calls a function specified by the set_unexpected()
- function. By default, unexpected() calls the function terminate(). In turn,
- terminate() calls abort() by default, terminating the program. For more
- details, see "set_unexpected() and set_terminate()".
-
-
- ΓòÉΓòÉΓòÉ 15.7.2. terminate() ΓòÉΓòÉΓòÉ
-
- In some cases, the exception handling mechanism will fail and a call to
- terminate() will be made. This terminate() call occurs in any of the following
- situations:
-
- o When terminate() is explicitly called
-
- o When no catch can be matched to a thrown object
-
- o When the stack becomes corrupted during the exception-handling process
-
- o When a system defined unexpected() is called.
-
- terminate() calls abort(), which exits from the program. You can replace this
- call to terminate() with another function by using the set_terminate()
- function.
-
-
- ΓòÉΓòÉΓòÉ 15.7.3. set_unexpected() and set_terminate() ΓòÉΓòÉΓòÉ
-
- The function unexpected(), when invoked, calls the function most recently
- supplied as an argument to set_unexpected(). If set_unexpected() has not yet
- been called, unexpected() calls terminate().
-
- The function terminate(), when invoked, calls the function most recently
- supplied as an argument to set_terminate(). If set_terminate() has not yet been
- called, terminate() calls abort(), which ends the program.
-
- You can use set_unexpected() and set_terminate() to replace terminate() and
- abort(), respectively, with your own functions. set_unexpected() and
- set_terminate() are included in the standard header files <terminate.h> and
- <unexpected.h>. Each of these functions has as its return type and its argument
- type a pointer to function with a void return type and no arguments. The
- pointer to function you supply as the argument becomes the function called by
- the corresponding special function: the argument to set_unexpected() becomes
- the function called by unexpected(), and the argument to set_terminate()
- becomes the function called by terminate(). Both set_unexpected() and
- set_terminate() return a pointer to the function that was previously called by
- their respective special functions (unexpected() and terminate()). By saving
- the return values, you can restore the original special functions later so that
- unexpected() and terminate() will once again call terminate() and abort().
-
- If you use set_terminate() to define your own function to replace abort(), the
- final action of that program should be to exit from the program. If you attempt
- to return from the function called by terminate(), abort() is called instead
- and the program ends.
-
- The following example, shows the flow of control and special functions used in
- exception handling:
-
- #include <terminate.h>
- #include <unexpected.h>
- #include <iostream.h>
- class X { /* ... */ };
- class Y { /* ... */ };
- class A { /* ... */ };
- // pfv type is pointer to function returning void
- typedef void (*pfv)();
- void my_terminate()
- { cout << "Call to my terminate" <<
- endl; }
- void my_unexpected()
- { cout << "Call to my unexpected" <<
- endl; }
- void f() throw(X,Y) // f() is permitted to throw objects
- of class
- // types X and Y only
- { A aobj;
- throw(aobj); // error, f() throws a class A object
- }
- main()
- {
- pfv old_term = set_terminate(my_terminate);
- pfv old_unex = set_unexpected(my_unexpected);
- try{ f(); }
- catch(X) { /* ... */ }
- catch(Y) { /* ... */ }
- catch (...) { /* ... */ }
-
- set_unexpected(old_unex);
- try { f();}
- catch(X) { /* ... */ }
- catch(Y) { /* ... */ }
- catch (...) { /* ... */ }
- }
-
- At run time, this program behaves as follows:
-
- 1. The call to set_terminate() assigns to old_term the address of the function
- last passed to set_terminate() when set_terminate() was previously called.
-
- 2. The call to set_unexpected() assigns to old_unex the address of the
- function last passed to set_unexpected() when set_unexpected() was
- previously called.
-
- 3. Within a try block, function f() is called. Because f() throws an
- unexpected exception, a call to unexpected() is made. unexpected() in turn
- calls my_unexpected(), which prints a message to standard output and
- returns.
-
- 4. The second call to set_unexpected() replaces the user-defined function
- my_unexpected() with the saved pointer to the original function
- (terminate()) called by unexpected().
-
- 5. Within a second try block, function f() is called once more. Because f()
- throws an unexpected exception, a call to unexpected() is again made.
- unexpected() automatically calls terminate(), which calls the function
- myterminate().
-
- 6. myterminate() displays a message, it returns, and the system calls abort()
- which terminates the program.
-
- At run time, the following information is displayed, and the program ends:
-
- Call to my_unexpected
- Call to my_terminate
-
- Note: The catch blocks following the try block are not entered, because the
- exception was handled by my_unexpected() as an unexpected throw, not as a valid
- exception.
-
-
- ΓòÉΓòÉΓòÉ 15.8. Related Information ΓòÉΓòÉΓòÉ
-
- "Expressions and Operators"
-
- "Constructors and Destructors"
-
-
- ΓòÉΓòÉΓòÉ 16. Chapter 16. The Preprocessor ΓòÉΓòÉΓòÉ
-
- This chapter describes C++ preprocessing. It discusses the following topics:
-
- o Introduction to the preprocessor
- o Preprocessor directive format
- o Phases of preprocessing
- o Macro definition and expansion
- o The # operator
- o Macro concatenation with the ## operator
- o Scope of macro names and #undef
- o File inclusion using #include
- o Conditional compilation in C++
- o Line control in C++
- o Error directive (#error)
- o Pragmas
- o Null directive (#)
- o Predefined macro names
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 16.1. Introduction to the Preprocessor ΓòÉΓòÉΓòÉ
-
- Preprocessing is a step in the compilation process that enables you to:
-
- o Replace identifiers in the current file with specified source text
-
- o Imbed files within the current file
-
- o Conditionally compile sections of the current file
-
- o Change the line number of the next line of source and change the file name of
- the current file
-
- o Generate diagnostic messages.
-
- The preprocessor recognizes the following directives:
-
- o #define
- o #undef
- o #include
- o #if
- o #ifdef
- o #ifndef
- o #else
- o #elif
- o #endif
- o #line
- o #error
- o #pragma.
-
- This chapter also discusses:
-
- o The # operator
-
- o Macro concatenation with the ## operator
-
- o Null directive (#)
-
- o Predefined macros.
-
-
- ΓòÉΓòÉΓòÉ 16.2. Preprocessor Directive Format ΓòÉΓòÉΓòÉ
-
- Preprocessor directives begin with the # character, followed by a preprocessor
- keyword. White space can appear before the # character. These lines have syntax
- independent of the rest of the language. They have effects that last
- (independent of the scoping rules of C++ ) until the end of the compilation
- unit.
-
- A preprocessor directive ends at the end of a line unless the last character of
- the line is the \ (backslash) character. If the \ character appears as the last
- character in the preprocessor line, the preprocessor interprets the \ as a
- continuation marker. The preprocessor ignores the \ (and the following new-line
- character) and interprets the following line as a continuation of the current
- preprocessor line. The last character in a source file cannot be a backslash
- character.
-
- Except for some pragma directives, preprocessor directives can appear at any
- line in a program.
-
-
- ΓòÉΓòÉΓòÉ 16.3. Phases of Preprocessing ΓòÉΓòÉΓòÉ
-
- Preprocessing appears as if it occurs in several phases.
-
- 1. New-line characters are introduced as needed to replace system-dependent
- end-of-line indicators, and any other system-dependent character-set
- translations are done. Equivalent single characters replace trigraph
- sequences.
-
- 2. Each \ (backslash) followed by a new-line character pair is deleted. The
- next source line is appended to the line that contained the sequence.
-
- 3. The source text is decomposed into preprocessing tokens and sequences of
- white space. A single white space replaces each comment. A source file
- cannot end with a partial token or comment.
-
- 4. Preprocessing directives are executed and macros are expanded.
-
- 5. Escape sequences in character constants and string literals are replaced by
- their equivalent values.
-
- 6. Adjacent string literals are concatenated.
-
- The preprocessor output is syntactically and semantically analyzed and
- translated, and then linked as necessary with other programs and libraries.
-
-
- ΓòÉΓòÉΓòÉ 16.4. Macro Definition and Expansion (#define) ΓòÉΓòÉΓòÉ
-
- A preprocessor define directive directs the preprocessor to replace all
- subsequent occurrences of an identifier or macro with specified source text.
-
- The #define preprocessor directive has the form:
-
- #define identifier token-string
-
- #define identifier(
- identifier , ... ,
- identifier
- )
- token-string
-
- The #define directive can contain an object-like definition or a function-like
- definition.
-
-
- ΓòÉΓòÉΓòÉ 16.4.1. Object-Like Macro Definition ΓòÉΓòÉΓòÉ
-
- An object-like macro definition replaces a single identifier with the specified
- source text. The following definition causes the preprocessor to replace all
- subsequent instances of the identifier COUNT with the constant 1000:
-
- :id='51V01093'.
- #define COUNT 1000
-
- If the statement:
-
- :id='51V01095'.
- int arry[COUNT];
-
- appears in a file following the definition of COUNT, the preprocessor changes
- the statement to:
-
- :id='51V01097'.
- int arry[1000];
-
- in the output of the preprocessor.
-
- Other definitions can make reference to the identifier COUNT:
-
- :id='51V01099'.
- #define MAX_COUNT COUNT + 100
-
- The preprocessor replaces each subsequent occurrence of MAX_COUNT with COUNT +
- 100, which the preprocessor then replaces with 1000 + 100.
-
-
- ΓòÉΓòÉΓòÉ 16.4.2. Function-Like Macro Definition ΓòÉΓòÉΓòÉ
-
- A function-like definition is an identifier followed by a parenthesized
- argument list and the replacement code. The arguments are imbedded in the
- replacement code. White space cannot separate the identifier for the macro name
- and the left parenthesis of the argument list. A comma must separate each
- argument. For portability, do not use more than 31 arguments for a macro.
-
- A function-like macro invocation is an identifier followed by a parenthesized
- list of arguments. A comma must separate each argument. Once the preprocessor
- identifies a function-like macro invocation, argument substitution takes place.
- An argument in the replacement code is replaced by the corresponding argument
- in the parenthesized list. Any macro invocations contained in the argument
- itself are completely replaced before the argument is replaced.
-
- Note: :id='218TO1899'. Arguments of the # and ## operators are converted
- before replacement of arguments in a function-like macro.
-
- The following line defines the macro SUM as having two arguments, a and b, and
- the replacement code (a + b):
-
- :id='51V010a2'.
- #define SUM(a,b) (a + b)
-
- If the statements:
-
- :id='51V010a4'.
- c = SUM(x,y);
- c = d * SUM(x,y);
-
- appear after this definition and in the same file as the definition, the
- preprocessor changes the statement to:
-
- :id='51V010a6'.
- c = (x + y);
- c = d * (x + y);
-
- in the output of the preprocessor.
-
- Use parentheses to ensure correct evaluation of replacement text. For example,
- the definition:
-
- :id='218TO189b'.
- #define SQR(c) ((c) * (c))
-
- requires parentheses around each argument c in the definition to correctly
- evaluate an expression like:
-
- :id='218TO189d'.
- y = SQR(a + b);
-
- The preprocessor expands this statement to:
-
- :id='218TO189f'.
- y = ((a + b) * (a + b));
-
- Without parentheses in the definition, the correct order of evaluation is not
- preserved, and the preprocessor output is:
-
- :id='218TO18a1'.
- y = (a + b * a + b);
-
- See "Parenthesized Expressions" for more information about using parentheses.
-
-
- ΓòÉΓòÉΓòÉ 16.4.3. Notes ΓòÉΓòÉΓòÉ
-
- A macro call must have the same number of arguments as the corresponding macro
- definition has arguments. A macro call can specify an empty argument list.
-
- In the macro call argument list, commas that appear as character constants, in
- string literals or surrounded by parentheses, do not separate arguments.
-
- The scope of a macro definition begins at the definition and does not end until
- a corresponding #undef directive is encountered. If there is no corresponding
- #undef directive, the scope of the macro definition lasts until the end of the
- source file is reached.
-
- A recursive macro is not fully expanded. For example, the following definition:
-
- :id='51V010ac'.
- #define x(a,b) x(a+1,b+1) + 4
-
- would expand:
-
- :id='162TO14a4'.
- x(20,10)
-
- to
-
- :id='162TO14a6'.
- x(20+1,10+1) + 4
-
- rather than trying to expand the macro x over and over within itself.
-
- A definition is not required to specify replacement code. The following
- definition removes all instances of the word debug from subsequent lines in the
- current file:
-
- :id='51V010b0'.
- #define debug
-
- This is the same as specifying the -Ddebug= compiler option. Note that
- specifying -Ddebug without the = (equal sign) gives the digit 1 as replacement
- text.
-
- If you want to change the definition of a defined identifier, you must have an
- #undef directive before the second #define directive. The #undef directive
- nullifies the first definition so that the same identifier can be used in a
- redefinition.
-
- Within the text of the program, the preprocessor does not scan character
- constants, string literals, or comments for macro calls.
-
- The following program contains two macro definitions and a macro call that
- references both of the defined macros:
-
- :id='51V010b5'.
- #include <iostream.h>
- #define SQR(s) ((s) * (s))
- #define PRNT(a,b)\
- cout << "value 1 = " << a;\
- cout << "value 2 = " << b;
- void main()
- {
- int x = 2;
- int y = 3;
- PRNT(SQR(x),y);
- }
-
- After being interpreted by the preprocessor, this program is replaced by code
- equivalent to the following:
-
- :id='51V010b7'.
- void main()
- {
- int x = 2;
- int y = 3;
- cout << "value 1 = " << ((x) * (x));
- cout << "value 2 = " << y;
- }
-
- This program produces the following output:
-
- :id='51V010b9'.
- value 1 = 4
- value 2 = 3
-
-
- ΓòÉΓòÉΓòÉ 16.5. The # Operator ΓòÉΓòÉΓòÉ
-
- The # (single number sign) operator converts an argument of a function-like
- macro into a character string literal. If a macro ABC is defined using the
- following directive:
-
- :id='51V01141'.
- #define ABC(x) #x
-
- all subsequent occurrences of the macro ABC are expanded into a character
- string literal containing the argument passed to ABC.
-
- For example: :id='162TO14a9'. Invocation Result of Macro Expansion
-
- :id='162TO14aa'.
- ABC(1) "1"
-
- :id='162TO14ab'.
- ABC(Hello there) "Hello there"
-
-
- ΓòÉΓòÉΓòÉ 16.5.1. Using the # Operator in a Function-Like Macro Definition ΓòÉΓòÉΓòÉ
-
- When you use the # operator in a function-like macro definition, the following
- rules apply: An argument in a function-like macro that is preceded by the #
- operator is converted into a character string literal containing the argument
- passed to the macro. White-space characters that appear before or after the
- argument passed to the macro are deleted. Multiple white-space characters
- imbedded within the argument passed to the macro are replaced by a single-space
- character. If the argument passed to the macro contains a string literal and if
- a \ (backslash) character appears within the literal, a second \ character is
- inserted before the original \ when the macro is expanded. If the argument
- passed to the macro contains a " (double quotation mark) character, a \
- character is inserted before the " when the macro is expanded. If the argument
- passed to the macro contains a ' (single quotation mark) character, a \
- character is inserted before the ' when the macro is expanded. The conversion
- of an argument into a string literal occurs before macro expansion. If more
- than one ## operator and/or # operator appears in the replacement list of a
- macro definition, the order of evaluation of the operators is not defined. If
- the result of the macro expansion is not a valid character string literal, the
- behavior is undefined.
-
- The following examples demonstrate these rules.
-
- :id='51V01150'.
- #define STR(x) #x
- #define XSTR(x) STR(x)
- #define ONE 1
- :id='162TO14ac'. Invocation Result of Macro Expansion
-
- :id='162TO14ad'.
- STR(\n "\n" '\n') "\n \"\\n\" '\\n'"
-
- :id='162TO14ae'.
- STR(ONE) "ONE"
-
- :id='162TO14af'.
- XSTR(ONE) "1"
-
- :id='162TO14b0'.
- XSTR("hello") "\"hello\""
-
-
- ΓòÉΓòÉΓòÉ 16.6. Macro Concatenation with the ## Operator ΓòÉΓòÉΓòÉ
-
- The ## (double number sign) operator is defined in ANSI for macro replacement.
- The ## operator concatenates two items (text and/or arguments) given in a macro
- definition. If a macro, XY, is defined using the following directive:
-
- :id='51V01155'.
- #define XY(x, y) x##y
-
- the two arguments passed to XY are concatenated. :id='162TO14b1'. Invocation
- Result of Macro Expansion
-
- :id='162TO14b2'.
- XY(1, 2) 12
-
- :id='162TO14b3'.
- XY(Green, house) Greenhouse
-
-
- ΓòÉΓòÉΓòÉ 16.6.1. The ## Operator ΓòÉΓòÉΓòÉ
-
- Use the ## operator according to the following constraints: The ## operator
- cannot be the very first or very last item in the replacement list of a macro
- definition. The argument before the ## operator is concatenated with the
- argument after the ## operator. Concatenation takes place before any arguments
- are expanded. If the result of a concatenation contains valid macro names,
- further macro expansions can take place. If more than one ## operator and/or #
- operator appears in the replacement list of a macro definition, the order of
- evaluation of the operators is not defined.
-
- The following examples demonstrate the use of the ## operator.
-
- :id='51V01160'.
- #define ArgArg(x, y) x##y
- #define ArgText(x) x##TEXT
- #define TextArg(x) TEXT##x
- #define TextText TEXT##text
- #define Jitter 1
- #define bug 2
- #define Jitterbug 3
- :id='162TO14b4'. Invocation Result of Macro Expansion
-
- :id='162TO14b5'.
- ArgArg(lady,bug) ladybug
-
- :id='162TO14b6'.
- ArgText(con) conTEXT
-
- :id='162TO14b7'.
- TextArg(book) TEXTbook
-
- :id='162TO14b8'.
- TextText TEXTtext
-
- :id='162TO14b9'.
- ArgArg(Jitter,bug) 3
-
-
- ΓòÉΓòÉΓòÉ 16.7. Scope of Macro Names and #undef ΓòÉΓòÉΓòÉ
-
- Once defined, a preprocessor identifier remains defined and in scope
- (independent of the scoping rules of C++ ) until the end of a translation unit
- or until it is undefined by an #undef preprocessor directive.
-
- The #undef preprocessor directive has the form:
-
- :id='87V0578c'.
- #undef identifier
-
- If the identifier is not currently defined as a macro, #undef is ignored.
-
- The following directives define BUFFER and SQR:
-
- :id='51V010c1'.
- #define BUFFER 512
- #define SQR(x) ((x) * (x))
-
- The following directives nullify these definitions:
-
- :id='51V010c3'.
- #undef BUFFER
- #undef SQR
-
- Occurrences of the identifiers BUFFER and SQR that appear following these
- #undef directives are not substituted for the previously defined code. Once the
- definition of a macro has been removed by an #undef directive, the identifier
- can be used in a new #define directive.
-
-
- ΓòÉΓòÉΓòÉ 16.8. File Inclusion (#include) ΓòÉΓòÉΓòÉ
-
- A preprocessor include directive causes the preprocessor to replace the
- directive with the contents of the specified file.
-
- The #include preprocessor directive has the form:
-
- :id='87V0578f'.
- #include " filename "
-
- #include < filename
- >
-
- #include token-string
-
- If the file name is enclosed in double quotation marks, the preprocessor
- searches the place (for example, directories or libraries) that contains the
- source file, then a standard or specified sequence of places, until it finds
- the specified file. For example:
-
- :id='51V01100'.
- #include "payroll.h"
-
- If the file name is enclosed in the characters < and , the preprocessor
- searches only the standard or specified places for the specified file. For
- example:
-
- :id='51V01102'.
- #include <iostream.h>
-
- Otherwise, the preprocessor resolves macros contained on a #include directive.
- After macro replacement, the resulting character sequence must consist of a
- file name enclosed in either double quotation marks or the characters < and .
- For example:
-
- :id='51V01104'.
- #define MONTH <july.h>
- #include MONTH
-
- The -I compiler option specifies a search path if the file name in the #include
- directive is not an absolute path. See the -I compiler option in the
- Programming Guide. for more information.
-
- If you have a number of definitions that several files use, you can place all
- these definitions in one file and include that file in each file that must know
- the definitions. For example, the following file defs.h contains several
- definitions and an inclusion of an additional file of definitions:
-
- :id='51V01107'.
- /* defs.h */
- #define TRUE 1
- #define FALSE 0
- #define BUFFERSIZE 512
- #define MAX_ROW 66
- #define MAX_COLUMN 80
- int hour;
- int min;
- int sec;
- #include "mydefs.h"
-
- You can imbed the definitions that appear in defs.h with the following
- directive:
-
- :id='51V01109'.
- #include "defs.h"
-
- The preprocessor looks for the file defs.h first in the directory that contains
- the current source file. If the file is not found there, the preprocessor
- searches a sequence of specified or standard locations.
-
- The following example shows one way to combine the use of preprocessor
- directives. The #define directive defines a macro that represents the name of
- the C++ standard I/O header file. The #include directive makes the header file
- available to the C++ program.
-
- :id='51V0110c'.
- #define ABC <iostream.h>
- // .
- // .
- // .
- #include ABC // equivalent to specifying #include <iostream.h>
- // .
- // .
- // .
-
-
- ΓòÉΓòÉΓòÉ 16.8.1. Restrictions ΓòÉΓòÉΓòÉ
-
- The new-line character and the cannot appear in a file-name delimited by < and
- .
-
- The new-line character and the " (double quotation marks) character cannot
- appear in a file-name delimited by " and ", although can appear.
-
-
- ΓòÉΓòÉΓòÉ 16.9. Conditional Compilation in C++ ΓòÉΓòÉΓòÉ
-
- A preprocessor conditional compilation directive causes the preprocessor to
- conditionally suppress the compilation of portions of source code. These
- conditional compilation directives test a constant expression or an identifier
- to determine which portions of the source file the preprocessor should pass on
- to the &xcomp. and which portions should be removed from the source file during
- preprocessing. The preprocessor conditional compilation directive spans several
- lines:
-
- o The condition specification line
-
- o Lines containing code that the preprocessor passes on to the &xcomp. if the
- condition evaluates to a nonzero value (optional)
-
- o The #else line (optional)
-
- o Lines containing code that the preprocessor passes on to the &xcomp. if the
- condition evaluates to zero (optional)
-
- o The preprocessor #endif directive.
-
- Preprocessor conditional compilation has the form:
-
- conditional:
- if-part
- [elif-parts][else-part]
- endif-line
- if-part:
- if-line text
- if-line:
- #if constant-expression
- #ifdef identifier
- #ifndef identifier
-
- A preprocessor conditional compilation directive can have one of three types of
- conditions: #if, #ifdef, and #ifndef. These directives, along with the #elif,
- #else, and #endif directives, control which portions of the source file are
- passed on to the &xcomp..
-
- The following describes the use of each directive: :id='128TO117f'. Condition
- Description
-
- #if, #elif If the constant expression evaluates to a nonzero value, the source
- that immediately follows the condition is passed on to the &xcomp..
-
- #ifdef If the identifier specified is defined as a macro, the source that
- immediately follows the condition is passed on to the &xcomp..
-
- #ifndef If the identifier specified is not defined as a macro, the source
- that immediately follows the condition is passed on to the &xcomp..
-
- If the condition evaluates to 0 (zero) and the conditional
- compilation directive contains a preprocessor #elif directive, the
- condition of the #elif directive is evaluated. If the #elif condition
- evaluates to nonzero, the source text between this #elif and the next
- #elif or preprocessor #else directive is selected by the preprocessor
- to be passed on to the &xcomp.. The #elif directive cannot appear
- after the preprocessor #else directive.
-
- The #elif preprocessor directive has the following form:
-
- elif-parts:
-
- elif-line text
-
- elif-parts elif-line text
-
- elif-line:
-
- :id='87V05791'.
- # elif constant-expression
-
- If the condition evaluates to 0 (zero) and the conditional
- compilation directive contains a preprocessor #else directive, the
- source text located between the preprocessor #else directive and the
- preprocessor #endif directive is selected by the preprocessor to be
- passed on to the &xcomp..
-
- The #else preprocessor directive has the following form:
-
- else-part:
-
- else-line text
-
- else-line:
-
- :id='87V05792'.
- # else
-
- The #endif preprocessor directive ends the conditional compilation
- directive. The #endif directive has the form:
-
- endif-line:
-
- :id='87V05793'.
- # endif
-
- You can nest preprocessor conditional directives.
-
-
- ΓòÉΓòÉΓòÉ 16.9.1. #if, #elif ΓòÉΓòÉΓòÉ
-
- The #if keyword and the #elif keyword must be followed by an integral constant
- expression. The constant expression cannot contain C++ identifiers (for
- example, a sizeof expression or a type cast) because the preprocessor can only
- recognize identifiers defined by the #define directive.
-
- Note: :id='51V01120'. If a macro is not defined, a value of 0 (zero) is
- assigned to it. In the following example, TEST must be a macro identifier;
- otherwise, neither the #if macro nor the #elif macro will be passed to the
- &xcomp. :
-
- :id='51V01121'.
- #if TEST >= 1
- cout << "i = " << i <<
- endl;
- cout << "array[i] = " << array[i]
- << endl;
- #elif TEST < 0
- cout <<"array subscript out of bounds"
- << endl;
- #endif
-
- The constant expression can contain the keyword defined. It can be used only
- with the preprocessor keywords #if and #elif. The expression:
-
- :id='51V01123'.
- defined identifier
-
- or
-
- :id='51V01125'.
- defined (identifier)
-
- evaluates to 1 if the identifier is defined in the preprocessor; otherwise, to
- 0 (zero). For example:
-
- :id='51V01127'.
- #if defined(TEST1) || defined(TEST2)
-
-
- ΓòÉΓòÉΓòÉ 16.9.2. #ifdef ΓòÉΓòÉΓòÉ
-
- An identifier must follow the #ifdef keyword. The following example defines
- MAX_LEN to be 75 if EXTENDED is defined for the preprocessor. Otherwise,
- MAX_LEN is defined to be 50.
-
- :id='51V0112a'.
- #ifdef EXTENDED
- # define MAX_LEN 75
- #else
- # define MAX_LEN 50
- #endif
-
- A control line of the form:
-
- #ifdef identifier
-
- is equivalent to:
-
- #if defined identifier
-
-
- ΓòÉΓòÉΓòÉ 16.9.3. #ifndef ΓòÉΓòÉΓòÉ
-
- An identifier must follow the #ifndef keyword. The following example defines
- MAX_LEN to be 50 if EXTENDED is not defined for the preprocessor. Otherwise,
- MAX_LEN is defined to be 75.
-
- :id='51V0112d'.
- #ifndef EXTENDED
- # define MAX_LEN 50
- #else
- # define MAX_LEN 75
- #endif
-
- A control line of the form:
-
- #ifndef identifier
-
- is equivalent to:
-
- #if !defined identifier
-
- The following example shows how you can nest preprocessor conditional
- compilation directives:
-
- :id='51V01130'.
- #if defined(TARGET1)
- # define SIZEOF_INT 16
- # ifdef PHASE2
- # define MAX_PHASE 2
- # else
- # define MAX_PHASE 8
- # endif
- #elif defined(TARGET2)
- # define SIZEOF_INT 32
- # define MAX_PHASE 16
- #else
- # define SIZEOF_INT 32
- # define MAX_PHASE 32
- #endif
-
- The following program contains preprocessor conditional compilation directives:
-
- :id='51V01132'.
- 1 #include <iostream.h>
- 2 void main()
- 3 {
- 4 static int array[ ] = { 1, 2, 3, 4, 5 };
- 5 int i;
- 6 for (i = 0; i <= 4; i++)
- 7 {
- 8 array[i] *= 2;
- 9
- 10 #if TEST >= 1
- 11 cout << "i = " << i;
- 12 cout << "array[i] = " << array[i]
- << endl;
- 13 #endif
- 14 }
- 15 }
-
-
- ΓòÉΓòÉΓòÉ 16.10. Line Control in C++ ΓòÉΓòÉΓòÉ
-
- A preprocessor line control directive causes the next source line to be treated
- as having the specified number.
-
- The #line preprocessor directive has the form:
-
- :id='87V05794'.
- #line constant
- ["filename"]
-
- A file name specification enclosed in double quotation marks can follow the
- line number. If file-name appears, the directive sets the predefined macro
- __FILE__ to the specified file name. The directive sets the predefined macro
- __LINE__ so that the line number of the next source line is considered to be
- the specified constant.
-
- The identifier on a #line directive is subject to macro replacement. After
- macro replacement, the resulting character sequence must consist of a decimal
- constant, optionally followed by a file name enclosed in double quotation
- marks.
-
- Note: :id='218TO18ab'. The keyword line is optional. The directive:
-
- :id='218TO18ac'.
- # line 300
-
- is equivalent to:
-
- :id='218TO18ae'.
- # 300
-
- You can use line control directives to see more meaningful error messages. The
- following program uses line control directives to give each function an easily
- recognizable line number.
-
- :id='51V01139'.
- 1 #include <iostream.h>
- 2 #define LINE200 200
- 3
- 4 void main()
- 5 {
- 6 func_1();
- 7 func_2();
- 8 }
- 9
- 10 #line 100
- 11 func_1() /* This line is viewed as line 100 */
- 12 {
- 13 cout << "Func_1 - current line number is <<
- __LINE__ << endl;
- 14 }
- 15
- 16 #line LINE200
- 17 func_2()
- 18 {
- 19 cout << "Func_2 - current line number is " <<
- __LINE__ << endl;
- 20 }
-
- This program produces the following output:
-
- :id='51V0113b'.
- Func_1 - current line number is 102
- Func_2 - current line number is 202
-
-
- ΓòÉΓòÉΓòÉ 16.11. Error Directive (#error) ΓòÉΓòÉΓòÉ
-
- A preprocessor error directive causes the preprocessor to generate a severe (S)
- diagnostic message that includes the given token sequence. Preprocessing
- continues, but no object code is generated.
-
- The #error preprocessor directive has the form:
-
- :id='87V0578d'.
- #error token-string
-
- The directive:
-
- :id='51V010f8'.
- #error Error in TESTPGM1 - This section should not be compiled
-
- generates the error message:
-
- :id='218TO18a8'.
- Error in TESTPGM1 - This section should not be compiled
-
- The #error directive is useful as a safety check during compilation. For
- example, if your program uses preprocessor conditional compilation directives,
- place #error directives in the source file to prevent generation of object code
- if a particular section of the program is reached.
-
-
- ΓòÉΓòÉΓòÉ 16.12. Pragmas ΓòÉΓòÉΓòÉ
-
- A pragma is an implementation-defined instruction to the &xcomp.. It has the
- general form given below, where token-string is a series of characters giving a
- specific compiler instruction, and arguments, if any. Pragmas have the general
- form:
-
- #pragma token-string
-
- The token-string on a pragma is not subject to macro substitutions. More than
- one pragma option can be specified on a single #pragma directive.
-
- The following pragmas are available in C++ :
-
- o alloca
- o chars
- o comment
- o disjoint
- o isolated_call
- o langlvl
- o options
- o strings
- o define
- o implementation.
-
-
- ΓòÉΓòÉΓòÉ 16.12.1. alloca ΓòÉΓòÉΓòÉ
-
- The #pragma alloca directive has the form:
-
- :id='87V0579f'.
- pragma-alloca:
- #pragma alloca
-
- It specifies that the function, alloca(size_t size), is to allocate space for
- an object of size bytes. The allocated space is put on the stack.
-
- You must include the #pragma alloca directive to have the &xcomp. provide an
- inlined version of alloca. Alternatively, the -ma compiler option substitutes
- inline code for calls to function alloca without specifying the #pragma alloca
- directive in the source code. If #pragma alloca is unspecified, or if you do
- not use -ma, alloca is treated as a user-defined identifier, rather than as a
- built-in function.
-
- Whenever you make a call to alloca, you must include the header file <malloc.h>
- to define alloca.
-
- This pragma must be included in the source before the first function
- definition. Once specified, it applies to the rest of the file and cannot be
- turned off. If a source file contains any functions that you want compiled
- without #pragma alloca, place these functions in a different file.
-
-
- ΓòÉΓòÉΓòÉ 16.12.2. chars ΓòÉΓòÉΓòÉ
-
- The #pragma chars directive specifies that the &xcomp. is to treat all char
- objects as signed or unsigned.
-
- The #pragma chars directive has the form:
-
- pragma-chars:
-
- :id='87V0579e'.
- #pragma chars (
- sign
- )
-
- sign:
-
- signed
-
- unsigned
-
-
- ΓòÉΓòÉΓòÉ 16.12.3. comment ΓòÉΓòÉΓòÉ
-
- The #pragma comment directive places a comment into the object file.
-
- The #pragma comment directive has the form:
-
- pragma-comment:
-
- #pragma comment (
- comment-type
- )
-
- comment-type:
-
- :id='87V0579b'.
- compiler
-
- date
-
- timestamp
-
- copyright[,
- "token-string"]
-
- user[,
- "token-string"]
-
- The comment-type can be:
-
- compiler The name and version of the compiler is appended to the end of the
- generated object module.
-
- date The date and time of compilation is appended to the end of the
- generated object module.
-
- timestamp The date and time of the last modification of the source is appended
- to the end of the generated object module.
-
- copyright The text specified by the token-string is placed by the &xcomp. into
- the generated object module and is loaded into memory when the
- program is run.
-
- user The text specified by the token-string field is placed by the &xcomp.
- into the generated object but is not loaded into memory when the
- program is run.
-
-
- ΓòÉΓòÉΓòÉ 16.12.4. disjoint ΓòÉΓòÉΓòÉ
-
- The #pragma disjoint directive lists the identifiers that are not aliased to
- each other within the scope of their use.
-
- The #pragma disjoint directive has the form:
-
- pragma-disjoint:
- #pragma disjoint (
- disjoint-name-list
- )
-
- disjoint-name-list:
- disjoint-name
- disjoint-name-list ,
- disjoint-name
-
- disjoint-name:
- name
- disjoint-pointer
-
- disjoint-pointer:
- name
- * disjoint-pointer
-
- where name can be an identifier, operator-function-name,
- conversion-function-name, destructor, or a qualified-name.
-
- The directive informs the &xcomp. that none of the identifiers listed shares
- the same physical storage, which provides more opportunity for optimizations.
- If any identifiers actually share physical storage, the pragma may give
- incorrect results.
-
- The pragma can appear anywhere in the source program that a declaration is
- allowed. An identifier in the directive must be visible at the point in the
- program where the pragma appears. The identifiers listed cannot refer to any of
- the following:
-
- o A member of a class, structure, or union
- o A class, structure, or union tag
- o An enumeration constant
- o A label.
-
- The identifiers must be declared before they are used in the pragma. A pointer
- in the identifier list must not have been dereferenced or used as a function
- argument before appearing in the directive.
-
- The following example shows the use of the #pragma disjoint directive. Because
- external pointer ptr_a does not share storage with and never points to the
- external variable b, the assignment of 7 to the object that ptr_a points to
- will not change the value of b. Likewise, external pointer ptr_b does not share
- storage with and never points to the external variable a. The argument to
- another_function has the value 6.
-
- :id='128TO11b8'.
- int a, b, *ptr_a, *ptr_b;
- #pragma disjoint(*ptr_a, b) // *ptr_a never points
- to b
- #pragma disjoint(*ptr_b, a) // *ptr_b never points
- to a
- one_function()
- {
- b = 6;
- *ptra = 7; // Assignment will not change the value
- of b
- another_function(b); // Argument "b" has the
- value 6
- }
-
- The -qignprag compiler option causes aliasing pragmas to be ignored. Use this
- option to debug applications containing the #pragma disjoint directive.
-
-
- ΓòÉΓòÉΓòÉ 16.12.5. isolated_call ΓòÉΓòÉΓòÉ
-
- The #pragma isolated_call directive lists functions that do not alter data
- objects visible at the time of the function call.
-
- The #pragma isolated_call directive has the form:
-
- pragma-isolated-call:
- #pragma isolated_call (
- isolated_call-name-list
- )
-
- isolated_call-name-list:
- name
- isolated_call-name-list , name
-
- where name can be an identifier, operator-function-name,
- conversion-function-name, destructor, or a qualified-name.
-
- The pragma should appear before calls to the functions in the identifier list.
- The identifiers listed must be declared before they are used in the pragma.
- They must be of type function or a typedef of function. If a name refers to an
- overloaded function, all variants of that function declared before the pragma
- are marked as isolated calls.
-
- The pragma informs the &xcomp. that none of the functions listed has side
- effects. Accessing a volatile object, modifying an external object, modifying a
- file, or calling a function that does any of these can be considered side
- effects. Any change in the state of the run-time environment is considered a
- side effect. Passing function arguments by reference is one side effect that is
- allowed, but in general, functions with side effects can give incorrect results
- when listed in #pragma isolated_call directives.
-
- Marking a function as isolated indicates to the optimizer that external and
- static variables will not be changed by the called function and that references
- to storage can be deleted from the calling function where appropriate.
- Instructions can be reordered with more freedom, resulting in fewer pipeline
- delays and faster execution in the processor. Note that instruction reordering
- might, however, result in code that requires more values to be maintained
- across the isolated call. When the isolated call is not located in a loop, the
- overhead of saving and restoring extra registers might not be worth the savings
- that result from deleting the storage references.
-
- Functions specified in the identifier list are permitted to examine external
- objects and return results that depend on the state of the run-time
- environment. The functions can also modify the storage pointed to by any
- pointer arguments passed to the function; that is, calls by reference. Do not
- specify a function that calls itself or relies on local static storage. Listing
- such functions in the #pragma isolated_call directive can give unpredictable
- results.
-
- The following example shows the use of the #pragma isolated_call directive.
- Because the function this_function does not have side effects, a call to it
- will not change the value of the external variable a. The argument to
- other_function has the value 6.
-
- :id='128TO11ba'.
- int a, this_function(int); // Assumed to have no side
- effects
- #pragma isolated_call(this_function)
- that_function()
- {
- a = 6;
- this_function(7); // Call does not change the
- value of a
- other_function(a); // Argument "a" has the value
- 6
- }
-
- The -qignprag compiler option causes aliasing pragmas to be ignored. Use this
- option to debug applications containing the #pragma isolated_call directive.
-
-
- ΓòÉΓòÉΓòÉ 16.12.6. langlvl ΓòÉΓòÉΓòÉ
-
- The #pragma langlvl directive selects the C++ language level for compilation.
- It has the following form:
-
- pragma-langlvl:
- #pragma langlvl (
- language-level
- )
- language-level:
- ansi
- compat
- extended
-
- The &xcomp. uses predefined macros in the header files to make declarations and
- definitions available that define the specified language level. This pragma
- must appear before any statements in a file.
-
- o &ansilvl. defines the predefined macro __ANSI_ _ and undefines other
- langlvl variables. The default language level for the xlC compiler invocation
- command is &ansilvl. .
-
- o &saalvl. defines the predefined macro __COMPAT__ and undefines other langlvl
- variables.
-
- o &extlvl. defines the predefined macro __EXTENDED__ and undefines other
- langlvl variables.
-
-
- ΓòÉΓòÉΓòÉ 16.12.7. options ΓòÉΓòÉΓòÉ
-
- The #pragma options directive has the form:
-
- :id='87V057a0'.
- #pragma options option
- [ ... ]
-
- It specifies options to the &xcomp. in your source program. Except for #pragma
- options source, the #pragma options directive must be the first statement in
- your source program; only comments and blank lines can precede it.
-
- By default, the options specified apply to your entire source program. The
- #pragma options source directive and the other #pragma directives can be used
- throughout your program to turn an option on or off for a selected block of
- source code. If you specify more than one compiler option, use either a comma
- or a blank space to separate the options.
-
- See "Compiler Options" in the Programming Guide for detailed information about
- compiler options.
-
-
- ΓòÉΓòÉΓòÉ 16.12.8. strings ΓòÉΓòÉΓòÉ
-
- The #pragma strings directive has the form:
-
- pragma-strings:
-
- :id='87V0579d'.
- #pragma strings (
- storage-type
- )
-
- storage-type:
-
- readonly
-
- writable
-
- It specifies that the &xcomp. can place strings into read-only memory or must
- place strings into read/write memory. This pragma must appear before any C++
- code in a file. The default for ansi mode is readonly.
-
-
- ΓòÉΓòÉΓòÉ 16.12.9. define ΓòÉΓòÉΓòÉ
-
- The #pragma define is described in "The define and implementation Pragmas" in
- "Chapter 14. Templates".
-
-
- ΓòÉΓòÉΓòÉ 16.12.10. implementation ΓòÉΓòÉΓòÉ
-
- The #pragma implementation is described in "The define and implementation
- Pragmas" in "Chapter 14. Templates".
-
-
- ΓòÉΓòÉΓòÉ 16.13. Null Directive (#) ΓòÉΓòÉΓòÉ
-
- The null directive performs no action. It consists of a single # on a line of
- its own.
-
- In the following example, if MINVAL is a defined macro name, no action is
- performed. If MINVAL is not a defined identifier, it is defined as the value 1.
-
- :id='51V0113f'.
- #ifdef MINVAL
- #
- #else
- # define MINVAL 1
- #endif
-
-
- ΓòÉΓòÉΓòÉ 16.14. Predefined Macro Names ΓòÉΓòÉΓòÉ
-
- C++ provides predefined macro names to provide the following information during
- compilation.
-
-
- ΓòÉΓòÉΓòÉ 16.14.1. ANSI Standard Predefined Macro Names ΓòÉΓòÉΓòÉ
-
- __LINE__ An integer representing the current source line number. __LINE__ and
- __FILE__ can be set by the #line directive. For details, see "Line
- Control in C++ "
-
- __FILE__ A character string literal containing the name of the source file
- being compiled.
-
- :id='51V010cb'. __DATE__ A character string literal containing the date when
- the source file was compiled. The date is in the form:
-
- :id='51V010cc'.
- "Mmm dd yyyy"
-
- where:
-
- o Mmm represents the month in an abbreviated form (Jan, Feb, Mar, Apr, May,
- Jun, Jul, Aug, Sep, Oct, Nov, or Dec).
-
- o dd represents the day. If the day is less than 10, the first d is a blank
- character.
-
- o yyyy represents the year.
-
- o _ _TIME_ _ is a character string literal containing the time when the source
- file was compiled. The time is in the form:
-
- :id='51V010d2'.
- "hh:ss"
-
- where:
-
- o hh represents the hour.
-
- o mm represents the minutes.
-
- o ss represents the seconds.
-
- o _ _STDC_ _ is the integer 0 (zero), indicating that C++ does not conform to
- ANSI C.
-
-
- ΓòÉΓòÉΓòÉ 16.14.2. C++ Predefined Macro Names ΓòÉΓòÉΓòÉ
-
- __cplusplus The integer 1 (one) indicates that the compiler is a C++ compiler.
- This macro name has no trailing underscores.
-
- __TIMESTAMP__ A character string literal containing the date and time when the
- source file was last modified. The date and time are in the form:
-
- :id='51V010d8'.
- "Day Mmm dd hh:ss yyyy"
-
- where:
-
- o Day represents the day of the week (Mon, Tue, Wed, Thu, Fri, Sat, or Sun).
-
- o Mmm represents the month in an abbreviated form (Jan, Feb, Mar, Apr, May,
- Jun, Jul, Aug, Sep, Oct, Nov, or Dec).
-
- o dd represents the day of the month. If the day is less than 10, the first d
- is a blank character.
-
- o hh represents the hour.
-
- o mm represents the minutes.
-
- o ss represents the seconds.
-
- o yyyy represents the year.
-
- o __ANSI__ is a macro defined when the &ansilvl. language level is specified.
-
- o __COMPAT__ is a macro defined when the &saalvl. language level is specified.
-
- o __EXTENDED__ is a macro defined when the &extlvl. language level is
- specified.
-
- o __MATH__The &xcomp. can generate substitute code for calls to some math
- functions available in the standard C++ run-time libraries. The functions
- handled this way are defined as inline routines in
- /usr/lpp/xlC/include/math.h.
-
- o __STR__The &xcomp. can generate substitute code for calls to some string
- functions available in the standard C++ run-time libraries. The functions
- handled this way are defined as inline routines in
- /usr/lpp/xlC/include/string.h.
-
-
- ΓòÉΓòÉΓòÉ 16.14.3. Restrictions ΓòÉΓòÉΓòÉ
-
- Except for __MATH__ and __STR__, the predefined macro names cannot be the
- subject of a #define or #undef preprocessor directive. The preprocessor ignores
- any redefined macros and issues an error message.
-
-
- ΓòÉΓòÉΓòÉ 16.14.4. Notes ΓòÉΓòÉΓòÉ
-
- These predefined macro names consist of two underscore ( __ ) characters
- immediately preceding the name, the name in uppercase letters, and two
- underscore characters immediately following the name (except for __cplusplus).
-
- The value of __LINE__ changes during compilation as subsequent lines of your
- source program are processed. Also, the values of __FILE__ and __TIMESTAMP__
- change as any include files that are part of your source program are processed.
-
- The cout statements in the following program display the values of the
- predefined macros (__LINE__ , __FILE__ , __TIME__ , and __DATE__) and print a
- message indicating conformance to the ANSI C standard based on __STDC__ .
-
- :id='51V010ed'.
- #include <iostream.h>
- #if __STDC__
- # define CONFORM "conforms"
- #else
- # define CONFORM "does not conform"
- #endif
- void main()
- {
- cout << "Line " << __LINE__
- << " of file " << __FILE__
- << " has been executed.\n";
- cout << "This file was compiled on " <<
- __DATE__
- << ".\n";
- cout << "This compiler " << CONFORM
- << " to ANSI C standards.\n";
- }
-
-
- ΓòÉΓòÉΓòÉ 16.15. Related Information ΓòÉΓòÉΓòÉ
-
- "Lexical Conventions".
-
-
- ΓòÉΓòÉΓòÉ 17. Appendix A. C-C++ Compatibility ΓòÉΓòÉΓòÉ
-
- The differences between ANSI C and C++ fall into two categories:
-
- o Constructs found in C++ but not in ANSI C
- o Constructs found in both C++and ANSI C but treated differently in the two
- languages.
-
- You can also return to the table of contents
-
-
- ΓòÉΓòÉΓòÉ 17.1. C[++] Constructs Not Found in ANSI C ΓòÉΓòÉΓòÉ
-
- C++ contains many constructs that are not found in ANSI C. They include:
-
- o Single line comments beginning with //
-
- o Scope operator
-
- o Free store management using the operators new and delete
-
- o Linkage specification for functions
-
- o Reference types
-
- o Default arguments for functions
-
- o Inline functions
-
- o Classes
-
- o Anonymous unions
-
- o Overloaded operators and functions
-
- o Class templates and function templates
-
- o Exception handling
-
-
- ΓòÉΓòÉΓòÉ 17.2. Constructs Found in Both C[++] and ANSI C ΓòÉΓòÉΓòÉ
-
- Because C++ is based on ANSI C, the two languages have many constructs in
- common. The use of some of these shared constructs differs, as shown here.
-
-
- ΓòÉΓòÉΓòÉ 17.2.1. Character Array Initialization ΓòÉΓòÉΓòÉ
-
- In C++, when you initialize character arrays, a trailing '\0' (zero of type
- char) is appended to the string initializer. You cannot initialize a character
- array with more initializers than there are array elements.
-
- In ANSI C, space for the trailing '\0' can be omitted in this type of
- initialization.
-
- The following initialization, for instance, is not valid in C++ :
-
- char v[3] = "asd"; // not valid in C++, valid in ANSI C
-
- because four elements are required.This initialization produces an error
- because there is no space for the implied trailing '\0' (zero of type char).
- For more details, see "Array Initialization"
-
-
- ΓòÉΓòÉΓòÉ 17.2.2. Character Constants ΓòÉΓòÉΓòÉ
-
- A character constant has type char in C++ and int in ANSI C.
-
-
- ΓòÉΓòÉΓòÉ 17.2.3. Class and typedef Names ΓòÉΓòÉΓòÉ
-
- In C++, a class and a typedef cannot both use the same name to refer to a
- different type within the same scope (unless the typedef is a synonym for the
- class name). In C, a typedef name and a struct tag name declared in the same
- scope can have the same name because they have different name spaces. For
- example:
-
- void main ()
- {
- typedef double db;
- struct db; // error in C++, valid in ANSI C
-
- typedef struct st st; // valid ANSI C and C++
- }
-
-
- ΓòÉΓòÉΓòÉ 17.2.4. Class and Scope Declarations ΓòÉΓòÉΓòÉ
-
- In C++, a class declaration introduces the class name into the scope where it
- is declared and hides any object, function, or other declaration of that name
- in an enclosing scope. In ANSI C, an inner scope declaration of a struct name
- does not hide an object or function of that name in an outer scope. For
- example:
-
- double db;
- void main ()
- {
- struct db // hides double object db in C++
- { char* str; };
- int x = sizeof(db); // size of struct in C++
- // size of double in ANSI C
- }
-
-
- ΓòÉΓòÉΓòÉ 17.2.5. const Object Initialization ΓòÉΓòÉΓòÉ
-
- In C++, const objects must be initialized. In ANSI C, they can be left
- uninitialized. For more details, see "volatile and const Attributes"
-
-
- ΓòÉΓòÉΓòÉ 17.2.6. Definitions ΓòÉΓòÉΓòÉ
-
- An object declaration, for example:
-
- int i;
-
- is a definition in C++. In ANSI C it is a tentative definition.
-
- In C++, a global data object must be defined only once. In ANSI C, a global
- data object can be declared several times without using the extern keyword.
-
- In C++, multiple definitions for a single variable will cause an error. A C
- compilation unit can contain many identical tentative definitions for a
- variable.
-
- For more details, see "Declarations"
-
-
- ΓòÉΓòÉΓòÉ 17.2.7. Definitions Within Return or Argument Types ΓòÉΓòÉΓòÉ
-
- In C++, types may not be defined in return or argument types. ANSI C allows
- such definitions. For example, the declarations:
-
- void print(struct X { int i;} x); // error in C++
- enum count{one, two, three} counter(); // error in C++
-
- produce errors in C++ but are valid declarations in ANSI C. For more details,
- see "Function Declarations" , and "Calling Functions and Argument Passing"
-
-
- ΓòÉΓòÉΓòÉ 17.2.8. Enumerator Type ΓòÉΓòÉΓòÉ
-
- An enumerator has the same type as its enumeration in C++. In ANSI C, an
- enumeration has type int.
-
-
- ΓòÉΓòÉΓòÉ 17.2.9. Enumeration Type ΓòÉΓòÉΓòÉ
-
- The assignment to an object of enumeration type with a value that is not of
- that enumeration type will produce an error in C++. In ANSI C, an object of
- enumeration type can be assigned values of any integral type.
-
-
- ΓòÉΓòÉΓòÉ 17.2.10. Function Declarations ΓòÉΓòÉΓòÉ
-
- In C++, all declarations of a function must match the unique definition of a
- function. ANSI C has no such restriction. For more details, see "Function
- Declarations"
-
-
- ΓòÉΓòÉΓòÉ 17.2.11. Functions With an Empty Argument List ΓòÉΓòÉΓòÉ
-
- Consider the following function declaration:
-
- int f();
-
- In C++, this function declaration means that the function takes no arguments.
- In ANSI C, it could take any number of arguments, of any type.
-
-
- ΓòÉΓòÉΓòÉ 17.2.12. Global Constant Linkage ΓòÉΓòÉΓòÉ
-
- In C++, an object declared const has internal linkage, unless it has previously
- been given external linkage. In ANSI C, it has external linkage. For more
- details, see "Program Linkage"
-
-
- ΓòÉΓòÉΓòÉ 17.2.13. Jump Statements ΓòÉΓòÉΓòÉ
-
- C++ does not allow you to jump over declarations containing initializations.
- ANSI C does allow you to use jump statements for this purpose. For more
- details, see "Initialization within Compound Statements"
-
-
- ΓòÉΓòÉΓòÉ 17.2.14. Keywords ΓòÉΓòÉΓòÉ
-
- C++ contains some additional keywords not found in ANSI C. ANSI C programs that
- use these keywords as identifiers are not valid C++ programs: le cols='* * * *
- *'. asm friend operator public throw catch inline private template try class
- new protected this virtual delete :exmp.