Copyright: Copyright © 1998 Inprise Corporation.                      All rights reserved.                                                 This Help file was compiled on   Saturday, January 16, 1999 23:36:33.


Lexical elements

See also

These topics provide a formal definition of the C++Builder lexical elements. They describe the different categories of word-like units (tokens) recognized by a language.

See the topics listed under See Also to learn about lexical elements.

The tokens in C++Builder are derived from a series of operations performed on your programs by the compiler and its built-in preprocessor.

A C++Builder program starts as a sequence of ASCII characters representing the source code, created by keystrokes using a suitable text editor (such as the C++Builder editor). The basic program unit in C++Builder is the file. This usually corresponds to a named file located in RAM or on disk and having the extension .C or .CPP.

The preprocessor first scans the program text for special preprocessor directives (see Preprocessor directives for details). For example, the directive #include <inc_file> adds (or includes) the contents of the file inc_file to the program before the compilation phase. The preprocessor also expands any macros found in the program and include files.

In the tokenizing phase of compilation, the source code file is parsed (that is, broken down) into tokens and whitespace.


Whitespace

See also

Whitespace is the collective name given to spaces (blanks), horizontal and vertical tabs, newline characters, and comments. Whitespace can serve to indicate where tokens start and end, but beyond this function, any surplus whitespace is discarded. For example, the two sequences

int i; float f;

and

int i;

   float f;

are lexically equivalent and parse identically to give the six tokens:

 	int

 	i

 	;

 	float

 	f

 	;

The ASCII characters representing whitespace can occur within literal strings, in which case they are protected from the normal parsing process (they remain as part of the string). For example,

char name[] = "Borland International";

parses to seven tokens, including the single literal-string token "Borland International"

Line splicing with \

A special case occurs if the final newline character encountered is preceded by a backslash (\). The backslash and new line are both discarded, allowing two physical lines of text to be treated as one unit.

"Borland \

International"

is parsed as "Borland International" (see String constants for more information).


Comments

See also

Comments are pieces of text used to annotate a program. Comments are for the programmer's use only; they are stripped from the source text before parsing.

There are two ways to delineate comments: the C method and the C++ method. Both are supported by C++Builder, with an additional, optional extension permitting nested comments. If you are not compiling for ANSI compatibility, you can use any of these kinds of comments in both C and C++ programs.

You should also follow the guidelines on the use of whitespace and delimiters in comments discussed later in this topic to avoid other portability problems.

C comments

A C comment is any sequence of characters placed after the symbol pair /*. The comment terminates at the first occurrence of the pair */ following the initial /*. The entire sequence, including the four comment-delimiter symbols, is replaced by one space after macro expansion. Note that some C implementations remove comments without space replacements.

C++Builder does not support the nonportable token pasting strategy using /**/. Token pasting in C++Builder is performed with the ANSI-specified pair ##, as follows:

#define VAR(i,j)  (i/**/j)    /* won't work */

#define VAR(i,j)  (i##j)      /* OK in C++Builder */

#define VAR(i,j)  (i ## j)    /* Also OK */

In C++Builder,

int /* declaration */ i /* counter */;

parses as these three tokens:

int   i;

See Token Pasting with ## for a description of token pasting.

C++ comments

C++ allows a single-line comment using two adjacent slashes (//). The comment can start in any position, and extends until the next new line:

class X {  // this is a comment

... };

You can also use // to create comments in C code. This is specific to C++Builder.

Nested comments

ANSI C doesn't allow nested comments. The attempt to comment out a line

/*  int /* declaration */ i /* counter */; */

fails, because the scope of the first /* ends at the first */. This gives

i ; */

which would generate a syntax error.

By default, C++Builder won't allow nested comments, but you can override this with compiler options.

Delimiters and whitespace

In rare cases, some whitespace before /* and //, and after */, although not syntactically mandatory, can avoid portability problems. For example, this C++ code:

int i = j//* divide by k*/k;

+m;

parses as int i = j +m; not as

int i = j/k;

+m;

as expected under the C convention. The more legible

int i = j/ /* divide by k*/ k;

+m;

avoids this problem.


Tokens

See also

Tokens are word-like units recognized by a language. C++Builder recognizes six classes of tokens.

Here is the formal definition of a token:

 keyword

 identifier

 constant

 string-literal

 operator

 punctuator (also known as separators)

As the source code is scanned, tokens are extracted in such a way that the longest possible token from the character sequence is selected. For example, external would be parsed as a single identifier, rather than as the keyword extern followed by the identifier al.

See Token Pasting with ## for a description of token pasting.


Keywords

See also

Keywords are words reserved for special purposes and must not be used as normal identifier names.

If you use non-ANSI keywords in a program and you want the program to be ANSI compliant, always use the non-ANSI keyword versions that are prefixed with double underscores. Some keywords have a version prefixed with only one underscore; these keywords are provided to facilitate porting code developed with other compilers. For ANSI-specified keywords there is only one version.

Note:	Note that the keywords __try and try are an exception to the discussion above. The keyword try is required to match the catch keyword in the C++ exception-handling mechanism. try cannot be substituted by __try. The keyword __try can only be used to match the __except or __finally keywords. See the discussions on C++ exception handling and C-based structured exceptions under Win32 for more information.

Please see the Help table of contents for a complete categorical and alphabetical listing of keywords.


C++-specific keywords

A number of keywords are specific to C++ and are not available if you are writing a program in C only. Please see the Help table of contents for a complete categorical and alphabetical listing of these and other keywords.


Table of Borland C++ register pseudovariables
Table of C++Builder register pseudovariables

See also

_AH	_CL	_EAX	_ESP
_AL	_CS	_EBP	_FLAGS
_AX	_CX	_EBX	_FS
_BH	_DH	_ECX	_GS
_BL	_DI	_EDI	_SI
_BP	_DL	_EDX	_SP
_BX	_DS	_ES	_SS
_CH	_DX	_ESI
All but the _FLAGS and _EFLAGS register pseudovariables are associated with the general purpose, segment, address, and special purpose registers.

Use register pseudovariables anywhere that you can use an integer variable to directly access the corresponding 80x86 register.

The flags registers contain information about the state of the 80x86 and the results of recent instructions.


C++Builder keyword extensions

C++Builder provides a number of keywords that are not part of the ANSI Standard.

Please see the Help table of contents for a complete categorical and alphabetical listing of Library Routines. [Note: This topic is retained for cross-referencing purposes only.]


Identifiers

See also

Here is the formal definition of an identifier:

identifier:

nondigit

identifier nondigit

identifier digit

nondigit: one of

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

digit: one of

0  1  2  3  4  5  6  7  8  9

Naming and length restrictions

Identifiers are arbitrary names of any length given to classes, objects, functions, variables, user-defined data types, and so on. (Identifiers can contain the letters a to z and A to Z, the underscore character "_", and the digits 0 to 9.) There are only two restrictions:

 The first character must be a letter or an underscore.

 By default, C++Builder recognizes only the first 250 characters as significant. The number of significant characters can be reduced by menu and command-line options, but not increased.

Case sensitivity

C++Builder identifiers are case sensitive, so that Sum, sum and suM are distinct identifiers.

Global identifiers imported from other modules follow the same naming and significance rules as normal identifiers. However, C++Builder offers the option of suspending case sensitivity to allow compatibility when linking with case-insensitive languages. With the case-insensitive option, the globals Sum and sum are considered identical, resulting in a possible. "Duplicate symbol" warning during linking.

An exception to these rules is that identifiers of type __pascal are always converted to all uppercase for linking purposes.

Uniqueness and scope

Although identifier names are arbitrary (within the rules stated), errors result if the same name is used for more than one identifier within the same scope and sharing the same name space. Duplicate names are legal for different name spaces regardless of scope rules.


Constants

See also

Constants are tokens representing fixed numeric or character values.

C++Builder supports four classes of constants: integer, floating point, character (including strings), and enumeration.

Internal representation of numerical types shows how these types are represented internally.

The data type of a constant is deduced by the compiler using such clues as numeric value and the format used in the source code. The formal definition of a constant is shown in the following table.

Constants: Formal Definitions

constant:	nonzero-digit: one of

   floating-constant	1  2  3  4  5  6  7  8  9

   integer-constant

   numeration-constant

   character-constant

floating-constant:	octal-digit: one of

   fractional-constant <exponent-part> <floating-suffix>	 	0  1  2  3  4  5  6  7

   digit-sequence  exponent-part  <floating-suffix>

fractional-constant:	hexadecimal-digit: one of

   <digit-sequence>  .  digit-sequence	0  1  2  3  4  5  6  7  8  9

   digit-sequence  .	a  b  c  d  e  f

A  B  C  D  E  F

exponent-part:	 	integer-suffix:

   e  <sign> digit-sequence	unsigned-suffix  <long-suffix>

   E  <sign> digit-sequence	long-suffix  <unsigned-suffix>

sign: one of	unsigned-suffix: one of

   +  -	u  U

digit-sequence:	long-suffix: one of

   digit	l  L

   digit-sequence  digit

floating-suffix: one of	enumeration-constant:

   f   l   F   L	identifier

integer-constant:	character-constant

   decimal-constant  <integer-suffix>	 c-char-sequence

   octal-constant  <integer-suffix>

   hexadecimal-constant  <integer-suffix>

decimal-constant:	c-char-sequence:

   nonzero-digit	c-char

   decimal-constant  digit	c-char-sequence  c-char

octal-constant:	c-char:

   0	Any character in the source character set

   octal-constant  octal-digit	except the single-quote ('), backslash (\), or

newline character escape-sequence.

hexadecimal-constant:	escape-sequence: one of the following

   0 x hexadecimal-digit	\"          \'           \?          \\

   0 X hexadecimal-digit	\a          \b          \f          \n

   hexadecimal-constant  hexadecimal-digit	\o          \oo        \ooo    \r

\t           \v          \Xh...    \xh...


Integer constants

See also

Integer constants can be decimal (base 10), octal (base 8) or hexadecimal (base 16). In the absence of any overriding suffixes, the data type of an integer constant is derived from its value, as shown in C++Builder integer constants without L or U.. Note that the rules vary between decimal and nondecimal constants.

Decimal

Decimal constants from 0 to 4,294,967,295 are allowed. Constants exceeding this limit are truncated. Decimal constants must not use an initial zero. An integer constant that has an initial zero is interpreted as an octal constant. Thus,

int i = 10;  /*decimal 10 */

int i = 010; /*decimal 8 */

int i = 0;   /*decimal 0 = octal 0 */

Octal

All constants with an initial zero are taken to be octal. If an octal constant contains the illegal digits 8 or 9, an error is reported. Octal constants exceeding 037777777777 are truncated.

Hexadecimal

All constants starting with 0x (or 0X) are taken to be hexadecimal. Hexadecimal constants exceeding 0xFFFFFFFF are truncated.

long and unsigned suffixes

The suffix L (or l) attached to any constant forces the constant to be represented as a long. Similarly, the suffix U (or u) forces the constant to be unsigned. It is unsigned long if the value of the number itself is greater than decimal 65,535, regardless of which base is used. You can use both L and U suffixes on the same constant in any order or case: ul, lu, UL, and so on.

The data type of a constant in the absence of any suffix (U, u, L, or l) is the first of the following types that can accommodate its value:

Decimal	int, long int, unsigned long int
Octal	int, unsigned int, long int, unsigned long int
Hexadecimal	int, unsigned int, long int, unsigned long int
If the constant has a U or u suffix, its data type will be the first of unsigned int, unsigned long int that can accommodate its value.

If the constant has an L or l suffix, its data type will be the first of long int, unsigned long int that can accommodate its value.

If the constant has both u and l suffixes, (ul, lu, Ul, lU, uL, Lu, LU or UL), its data type will be unsigned long int.

C++Builder integer constants without L or U summarizes the representations of integer constants in all three bases. The data types indicated assume no overriding L or U suffix has been used.


__int8, __int16, __int32, __int64, unsigned __int64, extended integer types
Extended integer types

See also

Category

C++Builder keyword extensions

Description

You can specify the size for integer types. You must use the appropriate suffix when using extended integers.

Type	Suffix	Example	Storage

__int8	i8	__int8 c = 127i8;	8 bits

__int16	i16	__int16 s = 32767i16;	16 bits

__int32	i32	 __int32 i = 123456789i32;	32 bits

__int64	i64	__int64 big = 12345654321i64;	64 bits

unsigned __int64	ui64	unsigned __int64  hugeInt = 	64 bits

     1234567887654321ui64;


Borland C++ integer constant without L or U
C++Builder integer constants without L or U

See also

Decimal constants

0	to	32,767	int

32,768	to	2,147,483,647	long

2,147,483,648	to	4,294,967,295	unsigned long

> 4294967295	truncated

Octal constants

00	to	077777	int

010000	to	0177777	unsigned int

02000000	to	017777777777	long

020000000000	to	037777777777	unsigned long

> 037777777777	truncated

Hexadecimal constants

0x0000	to	0x7FFF	int

0x8000	to	0xFFFF	unsigned int

0x10000	to	0x7FFFFFFF	long

0x80000000	to	0xFFFFFFFF	unsigned long

>0xFFFFFFFF	truncated


Floating point constants
Floating-point constants

See also

A floating-point constant consists of:

 Decimal integer

 Decimal point

 Decimal fraction

 e or E and a signed integer exponent (optional)

 Type suffix: f or F or l or L (optional)

You can omit either the decimal integer or the decimal fraction (but not both). You can omit either the decimal point or the letter e (or E) and the signed integer exponent (but not both). These rules allow for conventional and scientific (exponent) notations.

Negative floating constants are taken as positive constants with the unary operator minus (-) prefixed.

Here are some examples:

Constant	Value

23.45e6	23.45  10^6

.0	0

0.	0.0

1.	1.0

-1.23	-1.23

2e-5	2.0  10^-5

3E+10	3.0  10^10

.09E34	0.09  10^34

In the absence of any suffixes, floating-point constants are of type double. However, you can coerce a floating constant to be of type float by adding an f or F suffix to the constant. Similarly, the suffix l or L forces the constant to be data type long double. The table below shows the ranges available for float, double, and long double.

C++Builder floating-point constant sizes and ranges

Type	Size (bits)	Range

float	32	3.4  10^-38 to 3.4  10^38

double	64	1.7  10^-308 to 1.7  10^308

long double	80	3.4  10^-4932 to 1.1  10^4932


Character constants

See also

A character constant is one or more characters enclosed in single quotes, such as 'A', '+', or '\n'. In C, single-character constants have data type int. In C++, a character constant has type char. Multicharacter constants in both C and C++ have data type int.

To learn more about character constants, see the following topics.

 Three char types

 Escape sequences

 Wide-character and multi-character constants

Note:	To compare sizes of character types, compile this as a C program and then as a C++ program.

#include <stdio.h>

#define CH 'x'       /* A CHARACTER CONSTANT */

void main(void) {

   char ch = 'x';    /* A char VARIABLE      */

   printf("\nSizeof int     = %d", sizeof(int) );

   printf("\nSizeof char    = %d", sizeof(char) );

   printf("\nSizeof ch      = %d", sizeof(ch) );

   printf("\nSizeof CH      = %d", sizeof(CH) );

   printf("\nSizeof wchar_t = %d", sizeof(wchar_t) );

}

Note:	Sizes are in bytes.

Sizes of character types

Output when compiled as C program	Output when compiled as C++ program

Sizeof int	=	4	Sizeof int	=	4

Sizeof char	=	1	Sizeof char	=	1

Sizeof ch	=	1	Sizeof ch 	=	1

Sizeof CH	=	4	Sizeof CH	=	1

Sizeof wchar_t	=	2	Sizeof wchar_t	=	2


The three char types

See also

One-character constants, such as 'A', '\t' and '007', are represented as int values. In this case, the low-order byte is sign extended into the high bit; that is, if the value is greater than 127 (base 10), the upper bit is set to -1 (=0xFF). This can be disabled by declaring that the default char type is unsigned.

The three character types, char, signed char, and unsigned char, require an 8-bit (one byte) storage. In C and C++Builder programs prior to version Borland C++ 4.0 , char was treated the same as signed char. The behavior of C programs is unaffected by the distinction between the three character types.

Note:	To retain the old behavior, use the -K2 command-line option and Borland C++ 3.1  header files and libraries.

In a C++ program, a function can be overloaded with arguments of type char, signed char, or unsigned char. For example, the following function prototypes are valid and distinct:

void func(char ch);

void func(signed char ch);

void func(unsigned char ch);

If only one of the above prototypes exists, it will accept any of the three character types. For example, the following is acceptable:

void func(unsigned char ch);

void main(void) {

  signed char ch = 'x';

  func(ch);

  }


Escape sequences

See also

The backslash character (\) is used to introduce an escape sequence, which allows the visual representation of certain nongraphic characters. For example, the constant \n is used to the single newline character.

A backslash is used with octal or hexadecimal numbers to represent the ASCII symbol or control code corresponding to that value; for example, '\03' for Ctrl-C or '\x3F' for the question mark. You can use any string of up to three octal or any number of hexadecimal numbers in an escape sequence, provided that the value is within legal range for data type char (0 to 0xff for C++Builder). Larger numbers generate the compiler error Numeric constant too large. For example, the octal number \777 is larger than the maximum value allowed (\377) and will generate an error. The first nonoctal or nonhexadecimal character encountered in an octal or hexadecimal escape sequence marks the end of the sequence.

Take this example.

printf("\x0072.1A Simple Operating System");

This is intended to be interpreted as \x007 and "2.1A Simple Operating System". However, C++Builder compiles it as the hexadecimal number \x0072 and the literal string "2.1A Simple Operating System".

To avoid such problems, rewrite your code like this:

printf("\x007" "2.1A Simple Operating System");

Ambiguities might also arise if an octal escape sequence is followed by a nonoctal digit. For example, because 8 and 9 are not legal octal digits, the constant \258 would be interpreted as a two-character constant made up of the characters \25 and 8.

The following table shows the available escape sequences.

C++Builder escape sequences

Note:	You must use \\ to represent an ASCII backslash, as used in operating system paths.

Sequence	Value	Char	What it does

\a	0x07	BEL	Audible bell

\b	0x08	BS	Backspace

\f	0x0C	FF	Formfeed

\n	0x0A	LF	Newline (linefeed)

\r	0x0D	CR	Carriage return

\t	0x09	HT	Tab (horizontal)

\v	0x0B	VT	Vertical tab

\\	0x5c	\	Backslash

\'	0x27	'	Single quote (apostrophe)

\"	0x22	"	Double quote

\?	0x3F	?	Question mark

\O	any	O=a string of up to three octal digits

\xH	any	H=a string of hex digits

\XH	any	H=a string of hex digits


Wide-character and multi-character constants

See also

Wide-character types can be used to represent a character that does not fit into the storage space allocated for a char type. A wide character is stored in a two-byte space. A character constant preceded immediately by an L is a wide-character constant of data type wchar_t (defined in stddef.h). For example:

wchar_t ch = L'AB';

When wchar_t is used in a C program it is a type defined in stddef.h header file. In a C++ program, wchar_t is a keyword that can represent distinct codes for any element of the largest extended character set in any of the supported locales. In C++, wchar_t is the same size, signedness, and alignment requirement as an int type.

A string preceded immediately by an L is a wide-character string. The memory allocation for a string is two bytes per character. For example:

wchar_t str = L"ABCD";

Multi-character constants

C++Builder also supports multi-character constants. Multi-character constants can consist of as many as four characters. For example, the constant, '\006\007\008\009' is valid only in an C++Builder program. Multi-character constants are always 32-bit int values. The constants are not portable to other C++ compilers.


String constants

See also

String constants, also known as string literals, form a special category of constants used to handle fixed sequences of characters. A string literal is of data type array-of- const char and storage class static, written as a sequence of any number of characters surrounded by double quotes:

"This is literally a string!"

The null (empty) string is written "".

The characters inside the double quotes can include escape sequences. This code, for example:

"\t\t\"Name\"\\\tAddress\n\n"

prints like this:

"Name"\       Address

"Name" is preceded by two tabs; Address is preceded by one tab. The line is followed by two new lines. The \" provides interior double quotes.

If you compile with the -A option for ANSI compatibility, the escape character sequence "\\", is translated to "\" by the compiler.

A literal string is stored internally as the given sequence of characters plus a final null character ('\0'). A null string is stored as a single '\0' character.

Adjacent string literals separated only by whitespace are concatenated during the parsing phase. In the following example,

#include <stdio.h>

int main() {

   char    *p;

   p = "This is an example of how C++Builder"
   " will\nconcatenate very long strings for you"
   " automatically, \nresulting in nicer"
 " looking programs.";

   printf(p);

   return(0);

}

The output of the program is

This is an example of how C++Builder will

concatenate very long strings for you automatically,

resulting in nicer looking programs.

You can also use the backslash (\) as a continuation character to extend a string constant across line boundaries:

puts("This is really \

a one-line string");


Enumeration constants

See also

Enumeration constants are identifiers defined in enum type declarations. The identifiers are usually chosen as mnemonics to assist legibility. Enumeration constants are integer data types. They can be used in any expression where integer constants are valid. The identifiers used must be unique within the scope of the enum declaration. Negative initializers are allowed. See Enumerations and enum (keyword) for a detailed look at enum declarations.

The values acquired by enumeration constants depend on the format of the enumeration declaration and the presence of optional initializers. In this example,

enum team { giants, cubs, dodgers };

giants, cubs, and dodgers are enumeration constants of type team that can be assigned to any variables of type team or to any other variable of integer type. The values acquired by the enumeration constants are

giants = 0, cubs = 1, dodgers = 2

in the absence of explicit initializers. In the following example,

enum team { giants, cubs=3, dodgers = giants + 1 };

the constants are set as follows:

giants = 0, cubs = 3, dodgers = 1

The constant values need not be unique:

enum team { giants, cubs = 1, dodgers = cubs - 1 };


Constants and internal representation

See also

ANSI C acknowledges that the size and numeric range of the basic data types (and their various permutations) are implementation-specific and usually derive from the architecture of the host computer. For C++Builder, the target platform is the IBM PC family (and compatibles), so the architecture of the Intel 8088 and 80x86  microprocessors governs the choices of internal representations for the various data types.

The following tables list the sizes and resulting ranges of the data types for C++Builder. Internal representation of numerical types shows how these types are represented internally.

32-bit data types, sizes, and ranges

Type	Size (bits)	Range	Sample applications

unsigned char	8	0 <= X <= 255	Small numbers and full PC character set

char	8	-128 <= X <= 127	Very small numbers and ASCII characters

short int	16	-32,768 <= X <= 32,767	Counting, small numbers, loop control

unsigned int	32	0 <= X <= 4,294,967,295	Large numbers and loops

int	32	-2,147,483,648 <= X <= 2,147,483,647	Counting, small numbers, loop control

unsigned long	32	0 <= X <= 4,294,967,295	Astronomical distances

enum	32	-2,147,483,648 <= X <= 2,147,483,647	Ordered sets of values

long	32	-2,147,483,648 <= X <= 2,147,483,647	Large numbers, populations

float	32	1.18  10^-38 < |X| < 3.40  10^38	Scientific (7-digit) precision)

double	64	2.23  10^-308 < |X| < 1.79  10^308	Scientific (15-digit precision)

long double	80	3.37  10^-4932 < |X| < 1.18  10^4932	Financial (18-digit precision)


Internal representation of numerical types

See also

32-bit integers

Floating-point types, always

s	=	Sign bit ( 0 = positive, 1 = negative)	Exponent bias (normalized values):
i	=	Position of implicit binary point	float: 127 (7FH)
1	=	Integer bit of significance:	double: 1,023 (3FFH)
		Stored in long double Implicit in float, double	long double: 16,383 (3FFFH)


Constant expressions

See also

A constant expression is an expression that always evaluates to a constant (it is evaluated at compile-time and it must evaluate to a constant that is in the range of representable values for its type). Constant expressions are evaluated just as regular expressions are. You can use a constant expression anywhere that a constant is legal. The syntax for constant expressions is:

constant-expression:

Conditional-expression

Constant expressions cannot contain any of the following operators, unless the operators are contained within the operand of a sizeof operator:

 Assignment

 Comma

 Decrement

 Function call

 Increment


Punctuators

See also

The C++Builder punctuators (also known as separators) are:

[ ]

( )

{ }

,

;

:

...

*

=

#

Most of these punctuators also function as operators.

Brackets

Open and close brackets indicate single and multidimensional array subscripts:

char ch, str[] = "Stan";

int mat[3][4];           /* 3 x 4 matrix */

ch = str[3];             /* 4th element */

  .

  .

  .

Parentheses

Open and close parentheses ( ) are used to group expressions, isolate conditional expressions, and indicate function calls and function parameters:

d = c * (a + b);	/* override normal precedence */

if (d == z) ++x;	/* essential with conditional statement */

func();	/* function call, no args */

int (*fptr)();	/* function pointer declaration */

fptr = func;	/* no () means func pointer */

void func2(int n);	/* function declaration with parameters */

Parentheses are recommended in macro definitions to avoid potential precedence problems during expansion:

#define CUBE(x) ((x) * (x) * (x))

The use of parentheses to alter the normal operator precedence and associativity rules is covered in Expressions.

Braces

Open and close braces { } indicate the start and end of a compound statement:

if (d == z)

{

   ++x;

   func();

}

The closing brace serves as a terminator for the compound statement, so a ; (semicolon) is not required after the }, except in structure or class declarations. Often, the semicolon is illegal, as in

if (statement)

   {};                  /* illegal semicolon */

else

Comma

The comma (,) separates the elements of a function argument list:

void func(int n, float f, char ch);

The comma is also used as an operator in comma expressions. Mixing the two uses of comma is legal, but you must use parentheses to distinguish them. Note that (exp1, exp2) evalutates both but is equal to the second:

func(i, j);                              /* call func with two args */

func((exp1, exp2), (exp3, exp4, exp5));  /* also calls func with two args! */

Semicolon

The semicolon (;) is a statement terminator. Any legal C or C++ expression (including the empty expression) followed by a semicolon is interpreted as a statement, known as an expression statement. The expression is evaluated and its value is discarded. If the expression statement has no side effects, C++Builder might ignore it.

a + b;    /* maybe evaluate a + b, but discard value */

++a;      /* side effect on a, but discard value of ++a */

;         /* empty expression = null statement */

Semicolons are often used to create an empty statement:

for (i = 0; i < n; i++)

{

   ;

}

Colon

Use the colon (:) to indicate a labeled statement:

start:    x=0;

   ƒ

goto start;

Labels are discussed in Labeled statements.

Ellipsis

The ellipsis (...) is three successive periods with no intervening whitespace. Ellipses are used in the formal argument lists of function prototypes to indicate a variable number of arguments, or arguments with varying types:

void func(int n, char ch,...);

This declaration indicates that func will be defined in such a way that calls must have at least two arguments, an int and a char, but can also have any number of additional arguments.

In C++, you can omit the comma before the ellipsis.

Asterisk (pointer declaration)

The asterisk  (*) in a variable declaration denotes the creation of a pointer to a type:

char *char_ptr;  /* a pointer to char is declared */

Pointers with multiple levels of indirection can be declared by indicating a pertinent number of asterisks:

int **int_ptr;         /* a pointer to an integer array */

double ***double_ptr;  /* a pointer to a matrix of doubles */

You can also use the asterisk as an operator to either dereference a pointer or as the multiplication operator:

i = *int_ptr;

a = b * 3.14;

Equal sign (initializer)

The equal sign (=) separates variable declarations from initialization lists:

char array[5] = { 1, 2, 3, 4, 5 };

int  x = 5;

In C++, declarations of any type can appear (with some restrictions) at any point within the code. In a C function, no code can precede any variable declarations.

In a C++ function argument list, the equal sign indicates the default value for a parameter:

int f(int i = 0) { ... }  /* Parameter i has default value of zero */

The equal sign is also used as the assignment operator in expressions:

int a, b, c;

a = b + c;

float *ptr = (float *) malloc(sizeof(float) * 100);

Pound sign (preprocessor directive)

The pound sign  (#) indicates a preprocessor directive when it occurs as the first nonwhitespace character on a line. It signifies a compiler action, not necessarily associated with code generation. See Preprocessor directives for more on the preprocessor directives.

# and ## (double pound signs) are also used as operators to perform token replacement and merging during the preprocessor scanning phase. See Token pasting.


Language structure

See also

These topics provide a formal definition of C++ language and its implementation in C++Builder. They describe the legal ways in which tokens can be grouped together to form expressions, statements, and other significant units.


Declarations

See also

This section briefly reviews concepts related to declarations: objects, storage classes, types, scope, visibility, duration, and linkage. A general knowledge of these is essential before tackling the full declaration syntax. Scope, visibility, duration, and linkage determine those portions of a program that can make legal references to an identifier in order to access its object.


Objects

See also

An object is a specific region of memory that can hold a fixed or variable value (or set of values). (This use of the word object is different from the more general term used in object-oriented languages.) Each value has an associated name and type (also known as a data type). The name is used to access the object. This name can be a simple identifier, or it can be a complex expression that uniquely references the object. The type is used

 	to determine the correct memory allocation required initially.

 	to interpret the bit patterns found in the object during subsequent accesses.

 	in many type-checking situations, to ensure that illegal assignments are trapped.

C++Builder supports many standard (predefined) and user-defined data types, including signed and unsigned integers in various sizes, floating-point numbers in various precisions, structures, unions, arrays, and classes. In addition, pointers to most of these objects can be established and manipulated in memory.

The C++Builder standard libraries and your own program and header files must provide unambiguous identifiers (or expressions derived from them) and types so that C++Builder can consistently access, interpret, and (possibly) change the bit patterns in memory corresponding to each active object in your program.

Objects and declarations

Declarations establish the necessary mapping between identifiers and objects. Each declaration associates an identifier with a data type. Most declarations, known as defining declarations, also establish the creation (where and when) of the object; that is, the allocation of physical memory and its possible initialization. Other declarations, known as referencing declarations, simply make their identifiers and types known to the compiler. There can be many referencing declarations for the same identifier, especially in a multifile program, but only one defining declaration for that identifier is allowed.

Generally speaking, an identifier cannot be legally used in a program before its declaration point in the source code. Legal exceptions to this rule (known as forward references) are labels, calls to undeclared functions, and class, struct, or union tags.

lvalues

An lvalue is an object locator: an expression that designates an object. An example of an lvalue expression is *P, where P is any expression evaluating to a non-null pointer. A modifiable lvalue is an identifier or expression that relates to an object that can be accessed and legally changed in memory. A const pointer to a constant, for example, is not a modifiable lvalue. A pointer to a constant can be changed (but its dereferenced value cannot).

Historically, the l stood for "left," meaning that an lvalue could legally stand on the left (the receiving end) of an assignment statement. Now only modifiable lvalues can legally stand to the left of an assignment statement. For example, if a and b are nonconstant integer identifiers with properly allocated memory storage, they are both modifiable lvalues, and assignments such as a = 1; and b = a + b are legal.

rvalues

The expression a + b is not an lvalue: a + b = a is illegal because the expression on the left is not related to an object. Such expressions are often called rvalues (short for right values).


Storage classes and types

See also

Associating identifiers with objects requires each identifier to have at least two attributes: storage class and type (sometimes referred to as data type). The C++Builder compiler deduces these attributes from implicit or explicit declarations in the source code.

Storage class dictates the location (data segment, register, heap, or stack) of the object and its duration or lifetime (the entire running time of the program, or during execution of some blocks of code). Storage class can be established by the syntax of the declaration, by its placement in the source code, or by both of these factors.

The type determines how much memory is allocated to an object and how the program will interpret the bit patterns found in the object's storage allocation. A given data type can be viewed as the set of values (often implementation-dependent) that identifiers of that type can assume, together with the set of operations allowed on those values. The compile-time operator, sizeof, lets you determine the size in bytes of any standard or user-defined type. See sizeof for more on this operator.


Scope

See also

The scope of an identifier is that part of the program in which the identifier can be used to access its object. There are six categories of scope: block (or local), function, function prototype, file, class (C++ only), and namespace (C++ only). These depend on how and where identifiers are declared.

 	Block. The scope of an identifier with block (or local) scope starts at the declaration point and ends at the end of the block containing the declaration (such a block is known as the enclosing block). Parameter declarations with a function definition also have block scope, limited to the scope of the block that defines the function.

 	Function. The only identifiers having function scope are statement labels. Label names can be used with goto statements anywhere in the function in which the label is declared. Labels are declared implicitly by writing label_name: followed by a statement. Label names must be unique within a function.

 	Function prototype. Identifiers declared within the list of parameter declarations in a function prototype (not part of a function definition) have function prototype scope. This scope ends at the end of the function prototype.

 	File. File scope identifiers, also known as globals, are declared outside of all blocks and classes; their scope is from the point of declaration to the end of the source file.

 	Class (C++). A class is a named collection of members, including data structures and functions that act on them. Class scope applies to the names of the members of a particular class.Classes and their objects have many special access and scoping rules; see Classes.

 	Condition (C++). Declarations in conditions are supported. Variables can be declared within the expression of if, while, and switch statements. The scope of the variable is that of the statement. In the case of an if statement, the variable is also in scope for the else block.

Name spaces

Name space is the scope within which an identifier must be unique. C uses four distinct classes of identifiers:

 	goto label names. These must be unique within the function in which they are declared.

 	Structure, union, and enumeration tags. These must be unique within the block in which they are defined. Tags declared outside of any function must be unique.

 	Structure and union member names. These must be unique within the structure or union in which they are defined. There is no restriction on the type or offset of members with the same member name in different structures.

 	Variables, typedefs, functions, and enumeration members. These must be unique within the scope in which they are defined. Externally declared identifiers must be unique among externally declared variables.


Visibility

See also

The visibility of an identifier is that region of the program source code from which legal access can be made to the identifier's associated object.

Scope and visibility usually coincide, though there are circumstances under which an object becomes temporarily hidden by the appearance of a duplicate identifier: the object still exists but the original identifier cannot be used to access it until the scope of the duplicate identifier is ended.

Note:	Visibility cannot exceed scope, but scope can exceed visibility.

    .

    .

    .

{

   int i; char ch;  // auto by default

   i = 3;           // int i and char ch in scope and visible

    .

    .

    .

   {

      double i;

      i = 3.0e3;    // double i in scope and visible

                    // int i=3 in scope but hidden

      ch = 'A';     // char ch in scope and visible

   }

                    // double i out of scope

   i += 1;          // int i visible and = 4

    .

    .

    .

// char ch still in scope & visible = 'A'

}

    .

    .

    .

// int i and char ch out of scope

Again, special rules apply to hidden class names and class member names: C++ operators allow hidden identifiers to be accessed under certain conditions


Duration

See also

Duration, closely related to storage class, defines the period during which the declared identifiers have real, physical objects allocated in memory. We also distinguish between compile-time and run-time objects. Variables, for instance, unlike typedefs and types, have real memory allocated during run time. There are three kinds of duration: static, local, and dynamic.

Static

Memory is allocated to objects with static duration as soon as execution is underway; this storage allocation lasts until the program terminates. Static duration objects usually reside in fixed data segments allocated according to the memory model in force, although in 32-bit development, only the flat memory model is supported. All functions, wherever defined, are objects with static duration. All variables with file scope have static duration. Other variables can be given static duration by using the explicit static or extern storage class specifiers.

Static duration objects are initialized to zero (or null) in the absence of any explicit initializer or, in C++, constructor.

Don't confuse static duration with file or global scope. An object can have static duration and local scope

Local

Local duration objects, also known as automatic objects, lead a more precarious existence. They are created on the stack (or in a register) when the enclosing block or function is entered. They are deallocated when the program exits that block or function. Local duration objects must be explicitly initialized; otherwise, their contents are unpredictable. Local duration objects must always have local or function scope. The storage class specifier auto can be used when declaring local duration variables, but is usually redundant, because auto is the default for variables declared within a block. An object with local duration also has local scope, because it does not exist outside of its enclosing block. The converse is not true: a local scope object can have static duration.

When declaring variables (for example, int, char, float), the storage class specifier register also implies auto; but a request (or hint) is passed to the compiler that the object be allocated a register if possible. C++Builder can be set to allocate a register to a local integral or pointer variable, if one is free. If no register is free, the variable is allocated as an auto, local object with no warning or error.

Note:	The C++Builder compiler can ignore requests for register allocation. Register allocation is based on the compiler's analysis of how a variable is used.

Dynamic

Dynamic duration objects are created and destroyed by specific function calls during a program. They are allocated storage from a special memory reserve known as the heap, using either standard library functions such as malloc, or by using the C++ operator new. The corresponding deallocations are made using free or delete.


static

Example	Keywords

Syntax

static <data definition> ;

static <function name> <function definition> ;

Description

Use the static storage class specifier with a local variable to preserve the last value between successive calls to that function. A static variable acts like a local variable but has the lifetime of an external variable.

In a class, data and member functions can be declared static. Only one copy of the static data exists for all objects of the class.

A static member function of a global class has external linkage. A member of a local class has no linkage. A static member function is associated only with the class in which it is declared. Therefore, such member functions cannot be virtual.

Static member functions can only call other static member functions and only have access to static data. Such member functions do not have a this pointer.


Translation units

See also

The term translation unit refers to a source code file together with any included files, but less any source lines omitted by conditional preprocessor directives. Syntactically, a translation unit is defined as a sequence of external declarations:

translation-unit:

external-declaration

translation-unit external-declaration

external-declaration

function-definition

declaration

word external has several connotations in C; here it refers to declarations made outside of any function, and which therefore have file scope. (External linkage is a distinct property; see the section Linkage.) Any declaration that also reserves storage for an object or function is called a definition (or defining declaration). For more details, see External declarations and definitions.


Linkage

See also

An executable program is usually created by compiling several independent translation units, then linking the resulting object files with preexisting libraries. A problem arises when the same identifier is declared in different scopes (for example, in different files), or declared more than once in the same scope. Linkage is the process that allows each instance of an identifier to be associated correctly with one particular object or function. All identifiers have one of three linkage attributes, closely related to their scope: external linkage, internal linkage, or no linkage. These attributes are determined by the placement and format of your declarations, together with the explicit (or implicit by default) use of the storage class specifier static or extern.

Each instance of a particular identifier with external linkage represents the same object or function throughout the entire set of files and libraries making up the program. Each instance of a particular identifier with internal linkage represents the same object or function within one file only. Identifiers with no linkage represent unique entities.

External and internal linkage rules

 	Any object or file identifier having file scope will have internal linkage if its declaration contains the storage class specifier static.

For C++, if the same identifier appears with both internal and external linkage within the same file, the identifier will have external linkage. In C, it will have internal linkage.

 	If the declaration of an object or function identifier contains the storage class specifier extern, the identifier has the same linkage as any visible declaration of the identifier with file scope. If there is no such visible declaration, the identifier has external linkage.

 	If a function is declared without a storage class specifier, its linkage is determined as if the storage class specifier extern had been used.

 	If an object identifier with file scope is declared without a storage class specifier, the identifier has external linkage.

Identifiers with no linkage attribute:

 	Any identifier declared to be other than an object or a function (for example, a typedef identifier)

 	Function parameters

 	Block scope identifiers for objects declared without the storage class specifier extern

Name mangling

When a C++ module is compiled, the compiler generates function names that include an encoding of the function's argument types. This is known as name mangling. It makes overloaded functions possible, and helps the linker catch errors in calls to functions in other modules. However, there are times when you won't want name mangling. When compiling a C++ module to be linked with a module that does not have mangled names, the C++ compiler has to be told not to mangle the names of the functions from the other module. This situation typically arises when linking with libraries or .OBJ files compiled with a C compiler

To tell the C++ compiler not to mangle the name of a function, declare the function as extern "C", like this:

extern "C" void Cfunc( int );

This declaration tells the compiler that references to the function Cfunc should not be mangled.

You can also apply the extern "C" declaration to a block of names:

extern "C" {

   void Cfunc1( int );

   void Cfunc2( int );

   void Cfunc3( int );

};

As with the declaration for a single function, this declaration tells the compiler that references to the functions Cfunc1, Cfunc2, and Cfunc3 should not be mangled. You can also use this form of block declaration when the block of function names is contained in a header file:

extern "C" {

   #include "locallib.h"

};

Note: extern “C” cannot beused with class identifiers.


Declaration syntax
Introduction to declaration syntax

See also

All six interrelated attributes (storage classes, types, scope, visibility, duration, and linkage) are determined in diverse ways by declarations.

Declarations can be defining declarations (also known as definitions) or referencing declarations (sometimes known as nondefining declarations). A defining declaration, as the name implies, performs both the duties of declaring and defining; the nondefining declarations require a definition to be added somewhere in the program. A referencing declaration introduces one or more identifier names into a program. A definition actually allocates memory to an object and associates an identifier with that object.


Tentative definitions

See also

The ANSI C standard supports the concept of the tentative definition. Any external data declaration that has no storage class specifier and no initializer is considered a tentative definition. If the identifier declared appears in a later definition, then the tentative definition is treated as if the extern storage class specifier were present. In other words, the tentative definition becomes a simple referencing declaration.

If the end of the translation unit is reached and no definition has appeared with an initializer for the identifier, then the tentative definition becomes a full definition, and the object defined has uninitialized (zero-filled) space reserved for it. For example,

int x;

int x;           /*legal, one copy of x is reserved */

int y;

int y = 4;       /* legal, y is initialized to 4 */

int z = 5;

int z = 6;       /* not legal, both are initialized definitions */

Unlike ANSI C, C++ doesn't have the concept of a tentative declaration; an external data declaration without a storage class specifier is always a definition.


Possible declarations

See also

The range of objects that can be declared includes

 	Variables

 	Functions

 	Classes and class members (C++)

 	Types

 	Structure, union, and enumeration tags

 	Structure members

 	Union members

 	Arrays of other types

 	Enumeration constants

 	Statement labels

 	Preprocessor macros

The full syntax for declarations is shown in Tables 2.1 through 2.3. The recursive nature of the declarator syntax allows complex declarators. You'll probably want to use typedefs to improve legibility.

In Borland C++ declaration syntax, note the restrictions on the number and order of modifiers and qualifiers. Also, the modifiers listed are the only addition to the declarator syntax that are not ANSI C or C++. These modifiers are each discussed in greater detail in Variable Modifiers and Function Modifiers.

C++Builder declaration syntax

declaration:	elaborated-type-specifier:

<decl-specifiers>  <declarator-list>;	class-key  identifier

asm-declaration	class-key  class-name

function-declaration	enum enum-name

linkage-specification	class-key: (C++ specific)

decl-specifier:	class

storage-class-specifier	struct

type-specifier	union

function-specifier	enum-specifier:

friend (C++ specific)	enum <identifier> { <enum-list> }

typedef	enum-list:

decl-specifiers:	enumerator

<decl-specifiers> decl-specifier	enumerator-list , enumerator

storage-class-specifier:	enumerator:

auto	identifier

register	identifier = constant-expression

static	constant-expression:

extern	conditional-expression

function-specifier: (C++ specific)	linkage-specification: (C++ specific)

inline	extern string { <declaration-list> }

virtual	extern string declaration

simple-type-name:	type-specifier:

class-name	simple-type-name

typedef-name	class-specifier

boolean

char	enum-specifier

short	elaborated-type-specifier

int	const

__int8

__int16

__int32

__int64

long	volatile

signed	declaration-list:

unsigned	declaration

float	declaration-list ; declaration

double

void

declarator-list:	type-name:

init-declarator	type-specifier <abstract-declarator>

declarator-list  ,  init-declarator	abstract-declarator:

init-declarator:	pointer-operator <abstract-declarator>

declarator <initializer>	<abstract-declarator> ( argument-declaration-list )

declarator:	<cv-qualifier-list>

dname	<abstract-declarator> [ <constant-expression> ]

modifier-list	( abstract-declarator )

pointer-operator declarator	argument-declaration-list:

declarator ( parameter-declaration-list ) 	<arg-declaration-list>

<cv-qualifier-list >	arg-declaration-list , ...

(The <cv-qualifier-list > is for C++ only.)	<arg-declaration-list> ... (C++ specific)

declarator [ <constant-expression> ]	arg-declaration-list:

( declarator )	argument-declaration

modifier-list:	arg-declaration-list , argument-declaration

modifier	argument-declaration:

modifier-list  modifier	decl-specifiers declarator

modifier:	decl-specifiers declarator = expression

__cdecl	(C++ specific)

__pascal	decl-specifiers <abstract-declarator>

__stdcall	decl-specifiers <abstract-declarator> = expression

__fastcall	(C++ specific)

function-definition:

function-body:

pointer-operator:	compound-statement

* <cv-qualifier-list>	initializer:

& <cv-qualifier-list> (C++ specific)	= expression

class-name :: * <cv-qualifier-list> 	= { initializer-list }

(C++ specific)	( expression-list ) (C++ specific)

cv-qualifier-list:	initializer-list:

cv-qualifier <cv-qualifier-list>	expression

cv-qualifier	initializer-list , expression

const	{ initializer-list <,> }

volatile

dname:

name

class-name (C++ specific)

~ class-name (C++ specific)

type-defined-name


External declarations and definitions

See also

The storage class specifiers auto and register cannot appear in an external declaration. For each identifier in a translation unit declared with internal linkage, no more than one external definition can be given.

An external definition is an external declaration that also defines an object or function; that is, it also allocates storage. If an identifier declared with external linkage is used in an expression (other than as part of the operand of sizeof), then exactly one external definition of that identifier must be somewhere in the entire program.

C++Builder allows later re-declarations of external names, such as arrays, structures, and unions, to add information to earlier declarations. Here's an example:

int a[];              // no size

struct mystruct;      // tag only, no member declarators

  .

  .

  .

int a[3] = {1, 2, 3}; // supply size and initialize

struct mystruct {

   int i, j;

};                    // add member declarators

C++Builder class declaration syntax (C++ only) covers class declaration syntax. In the section on classes (beginning with Classes), you can find examples of how to declare a class. Referencing covers C++ reference types (closely related to pointer types) in detail. Finally, see Using Templates for a discussion of template-type classes.

C++Builder class declaration syntax (C++ only)

class-specifier:	base-specifier:

class-head { <member-list> }	 : base-list

class-head:	base-list:

class-key <identifier> <base-specifier>	base-specifier

class-key class-name <base-specifier>	base-list , base-specifier

member-list:	base-specifier:

member-declaration <member-list>	class-name

access-specifier : <member-list>	virtual <access-specifier> class-name

member-declaration:	access-specifier <virtual> class-name

<decl-specifiers> <member-declarator-list> ;	access-specifier:

function-definition <;>	private

qualified-name ;	protected

member-declarator-list:	public

member-declarator	conversion-function-name:

member-declarator-list, member-declarator	operator conversion-type-name

member-declarator:	conversion-type-name:

declarator <pure-specifier>	type-specifiers <pointer-operator>

<identifier> : constant-expression	constructor-initializer:

pure-specifier:	: member-initializer-list

= 0

member-initializer-list:	operator-name: one of

member-initializer	new  delete  sizeof  typeid

member-initializer , member-initializer-list	+	-	*	 /	%	^

member-initializer:	&	|	~	!	=	<>

class name ( <argument-list> )	+=	-=	=*	/=	%=	^=

identifier ( <argument-list> )	&=	|=	<<	>>	>>=	<<=

operator-function-name:	==	!=	<=	>=	&&	||

operator operator-name	++	__	,	->*	->	()

[ ]	.*


Type specifiers

See also

The type determines how much memory is allocated to an object and how the program interprets the bit patterns found in the object's storage allocation. A data type is the set of values (often implementation-dependent) identifiers can assume, together with the set of operations allowed on those values.

The type specifier with one or more optional modifiers is used to specify the type of the declared identifier:

int i;                   // declare i as an integer

unsigned char ch1, ch2;  // declare two unsigned chars

By long-standing tradition, if the type specifier is omitted, type signed int (or equivalently, int) is the assumed default. However, in C++, a missing type specifier can lead to syntactic ambiguity, so C++ practice requires you to explicitly declare all int type specifiers.

The type specifier keywords in C++Builder are:

char	float	signed	wchar_t

class	int	struct

double	long	union

enum	short	unsigned

Use the sizeof operators to find the size in bytes of any predefined or user-defined type.


Type categories

See also

The four basic type categories (and their subcategories) are as follows:

 	Aggregate

 	Array

 	struct

 	union

 	class (C++ only)

 	Function

 	Scalar

 	Arithmetic

 	Enumeration

 	Pointer

 	Reference (C++ only)

 	void

Types can also be viewed in another way: they can be fundamental or derived types. The fundamental types are void, char, int, float, and double, together with short, long, signed, and unsigned variants of some of these. The derived types include pointers and references to other types, arrays of other types, function types, class types, structures, and unions.

A class object, for example, can hold a number of objects of different types together with functions for manipulating these objects, plus a mechanism to control access and inheritance from other classes

Given any nonvoid type type (with some provisos), you can declare derived types as follows:

Declaring types

Declaration	Description

type t;	An object of type type

type array[10];	Ten types: array[0] - array[9]

type *ptr;	ptr is a pointer to type

type &ref = t;	ref is a reference to type (C++)

type func(void);	func returns value of type type

void func1(type t);	func1 takes a type type parameter

struct st {type t1; type t2};	structure st holds two types

Note:	type& var, type &var, and type & var are all equivalent.


void

Example	Keywords

Syntax

void identifier

Description

void is a special type indicating the absence of any value. Use the void keyword as a function return type if the function does not return a value.

void hello(char *name)

{

  printf("Hello, %s.",name);

}

Use void as a function heading if the function does not take any parameters.

int init(void)

{

  return 1;

}

Void Pointers

Generic pointers can also be declared as void, meaning that they can point to any type.

void pointers cannot be dereferenced without explicit casting because the compiler cannot determine the size of the pointer object.


The fundamental types

See also

The fundamental type specifiers are built from the following keywords:

char	__int8	long

double	__int16	signed

float	__int32	short

int	__int64	unsigned

From these keywords you can build the integral and floating-point types, which are together known as the arithmetic types. The modifiers long, short, signed, and unsigned can be applied to the integral types. The include file limits.h contains definitions of the value ranges for all the fundamental types.

Integral types

char, short, int, and long, together with their unsigned variants, are all considered integral data types. Integral types shows the integral type specifiers, with synonyms listed on the same line.

Integral types

char, signed char	Synonyms if default char set to signed.

unsigned char

char, unsigned char	Synonyms if default char set to unsigned.

signed char

int, signed int

unsigned, unsigned int

short, short int, signed short int

unsigned short, unsigned short int

long, long int, signed long int

unsigned long, unsigned long int

Note:	These synonyms are not valid in C++. See The three char types.

signed or unsigned can only be used with char, short, int, or long. The keywords signed and unsigned, when used on their own, mean signed int and unsigned int, respectively.

In the absence of unsigned, signed is assumed for integral types. An exception arises with char.  C++Builder lets you set the default for char to be signed or unsigned. (The default, if you don't set it yourself, is signed.) If the default is set to unsigned, then the declaration char ch declares ch as unsigned. You would need to use signed char ch to override the default. Similarly, with a signed default for char, you would need an explicit unsigned char ch to declare an unsigned char.

Only long or short can be used with int. The keywords long and short used on their own mean long int and short int.

ANSI C does not dictate the sizes or internal representations of these types, except to indicate that short, int, and long form a nondecreasing sequence with "short <= int <= long." All three types can legally be the same. This is important if you want to write portable code aimed at other platforms.

In a C++Builder 32-bit program, the types int and long are equivalent, both being 32 bits. The signed varieties are all stored in two's complement format using the most significant bit (MSB) as a sign bit: 0 for positive, 1 for negative (which explains the ranges shown in 32-bit data types, sizes, and ranges). In the unsigned versions, all bits are used to give a range of 0 - (2n - 1), where n is 8, 16, or 32.

Floating-point types

The representations and sets of values for the floating-point types are implementation dependent; that is, each implementation of C is free to define them. C++Builder uses the IEEE floating-point formats.See the topic on ANSI implementation-specific.

float and double are 32- and 64-bit floating-point data types, respectively. long can be used with double to declare an 80-bit precision floating-point identifier: long double test_case, for example.

The table of 32-bit data types, sizes, and ranges indicates the storage allocations for the floating-point types

Standard arithmetic conversions

When you use an arithmetic expression, such as a + b, where a and b are different arithmetic types, C++Builder performs certain internal conversions before the expression is evaluated. These standard conversions include promotions of "lower" types to "higher" types in the interests of accuracy and consistency.

Here are the steps C++Builder uses to convert the operands in an arithmetic expression:

1.	Any small integral types are converted as shown in Methods used in standard arithmetic conversions. After this, any two values associated with an operator are either int (including the long and unsigned modifiers), or they are of type double, float, or long double.

2.	If either operand is of type long double, the other operand is converted to long double.

3.	Otherwise, if either operand is of type double, the other operand is converted to double.

4.	Otherwise, if either operand is of type float, the other operand is converted to float.

5.	Otherwise, if either operand is of type unsigned long, the other operand is converted to unsigned long.

6.	Otherwise, if either operand is of type long, then the other operand is converted to long.

7.	Otherwise, if either operand is of type unsigned, then the other operand is converted to unsigned.

8.	Otherwise, both operands are of type int.

The result of the expression is the same type as that of the two operands.

Methods used in standard arithmetic conversions

Type	Converts to	Method

char	int	Zero or sign-extended (depends on default char type)

unsigned char	int	Zero-filled high byte (always)

signed char	int	Sign-extended (always)

short	int	Same value; sign extended

unsigned short	unsigned int	Same value; zero filled

enum	int	Same value

Special char, int, and enum conversions

Note:	The conversions discussed in this section are specific to C++Builder.

Assigning a signed character object (such as a variable) to an integral object results in automatic sign extension. Objects of type signed char always use sign extension; objects of type unsigned char always set the high byte to zero when converted to int.

Converting a longer integral type to a shorter type truncates the higher order bits and leaves low-order bits unchanged. Converting a shorter integral type to a longer type either sign-extends or zero-fills the extra bits of the new value, depending on whether the shorter type is signed or unsigned, respectively.


Initialization

See also

Initializers set the initial value that is stored in an object (variables, arrays, structures, and so on). If you don't initialize an object, and it has static duration, it will be initialized by default in the following manner:

 	To zero if it is an arithmetic type

 	To null if it is a pointer type

Note:	If the object has automatic storage duration, its value is indeterminate.

Syntax for initializers

initializer

= expression

= {initializer-list} <,>}

(expression list)

initializer-list

expression

initializer-list, expression

{initializer-list} <,>}

Rules governing initializers

 	The number of initializers in the initializer list cannot be larger than the number of objects to be initialized.

 	The item to be initialized must be an object (for example, an array).

 	For C (not required for C++), all expressions must be constants if they appear in one of these places:

 	In an initializer for an object that has static duration.

 	In an initializer list for an array, structure, or union (expressions using sizeof are also allowed).

 	If a declaration for an identifier has block scope, and the identifier has external or internal linkage, the declaration cannot have an initializer for the identifier.

 	If a brace-enclosed list has fewer initializers than members of a structure, the remainder of the structure is initialized implicitly in the same way as objects with static storage duration.

Scalar types are initialized with a single expression, which can optionally be enclosed in braces. The initial value of the object is that of the expression; the same constraints for type and conversions apply as for simple assignments.

For unions, a brace-enclosed initializer initializes the member that first appears in the union's declaration list. For structures or unions with automatic storage duration, the initializer must be one of the following:

 	An initializer list (as described in Arrays, structures, and unions).

 	A single expression with compatible union or structure type. In this case, the initial value of the object is that of the expression.

Arrays, structures, and unions

You initialize arrays and structures (at declaration time, if you like) with a brace-enclosed list of initializers for the members or elements of the object in question. The initializers are given in increasing array subscript or member order. You initialize unions with a brace-enclosed initializer for the first member of the union. For example, you could declare an array days, which counts how many times each day of the week appears in a month (assuming that each day will appear at least once), as follows:

int days[7] = { 1, 1, 1, 1, 1, 1, 1 }

The following rules initialize character arrays and wide character arrays:

 	You can initialize arrays of character type with a literal string, optionally enclosed in braces. Each character in the string, including the null terminator, initializes successive elements in the array. For example, you could declare

char name[] = { "Unknown" };

which sets up an eight-element array, whose elements are 'U' (for name[0]), 'n' (for name[1]), and so on (and including a null terminator).

 	You can initialize a wide character array (one that is compatible with wchar_t) by using a wide string literal, optionally enclosed in braces. As with character arrays, the codes of the wide string literal initialize successive elements of the array.

Here is an example of a structure initialization:

struct mystruct {

   int i;

   char str[21];

   double d;

   } s = { 20, "Borland", 3.141 };

Complex members of a structure, such as arrays or structures, can be initialized with suitable expressions inside nested braces.


Declarations and declarators

See also

A declaration is a list of names. The names are sometimes referred to as declarators or identifiers. The declaration begins with optional storage class specifiers, type specifiers, and other modifiers. The identifiers are separated by commas and the list is terminated by a semicolon.

Simple declarations of variable identifiers have the following pattern:

data-type var1 <=init1>, var2 <=init2>, ...;

where var1, var2,... are any sequence of distinct identifiers with optional initializers. Each of the variables is declared to be of type data-type. For example,

int x = 1, y = 2;

creates two integer variables called x and y (and initializes them to the values 1 and 2, respectively).

These are all defining declarations; storage is allocated and any optional initializers are applied.

The initializer for an automatic object can be any legal expression that evaluates to an assignment-compatible value for the type of the variable involved. Initializers for static objects must be constants or constant expressions.

In C++, an initializer for a static object can be any expression involving constants and previously declared variables and functions

The format of the declarator indicates how the declared name is to be interpreted when used in an expression. If type is any type, and storage class specifier is any storage class specifier, and if D1 and D2 are any two declarators, then the declaration

storage-class-specifier type D1, D2;

indicates that each occurrence of D1 or D2 in an expression will be treated as an object of type type and storage class storage class specifier. The type of the name embedded in the declarator will be some phrase containing type, such as "type," "pointer to type," "array of type," "function returning type," or "pointer to function returning type," and so on.

For example, in Declaration syntax examples each of the declarators could be used as rvalues (or possibly lvalues in some cases) in expressions where a single int object would be appropriate. The types of the embedded identifiers are derived from their declarators as follows:

Declaration syntax examples

Declarator syntax	Implied type of name	Example

type name;	type	int count;

type name[];	(open) array of type	int count[];

type name[3];	Fixed array of three elements,	int count[3];
all of type (name[0], name[1], and name[2]

type *name;	Pointer to type	int *count;

type *name[];	(open) array of pointers to type	int *count[];

type *(name[]);	Same as above	int *(count[]);

type (*name)[];	Pointer to an (open) array of type	int (*count) [];

type &name;	Reference to type (C++ only)	int &count;

type name();	Function returning type	int count();

type *name();	Function returning pointer to type	int *count();

type *(name());	Same as above	int *(count());

type (*name)();	Pointer to function returning type	int (*count) ();

Note the need for parentheses in (*name)[ ] and (*name)( ); this is because the precedence of both the array declarator [ ] and the function declarator ( ) is higher than the pointer declarator *. The parentheses in *(name[ ]) are optional.

Note:	See C++Builder declaration syntax for the declarator syntax. The definition covers both identifier and function declarators.


Storage class specifiers

Storage classes specifiers are also called type specifiers. They dictate the location (data segment, register, heap, or stack) of an object and its duration or lifetime (the entire running time of the program, or during execution of some blocks of code). Storage class can be established by the declaration syntax, by its placement in the source code, or by both of these factors.

The keyword mutable does not affect the lifetime of the class member to which it is applied.

The storage class specifiers in C++Builder are:

auto	register

__declspec	static

extern	typedef

mutable


Variable modifiers

See also

In addition to the storage class specifier keywords, a declaration can use certain modifiers to alter some aspect of the identifier. The modifiers available with C++Builder are summarized in C++Builder modifiers.

Mixed-language calling conventions

C++Builder allows your programs to easily call routines written in other languages, and vice versa. When you mix languages , you have to deal with two important issues: identifiers and parameter passing.

By default, C++Builder saves all global identifiers in their original case (lower, upper, or mixed) with an underscore "_" prepended to the front of the identifier. To remove the default, you can use the -u command-line option.

Note:	The section Linkage tells how to use extern, which allows C names to be referenced from a C++ program.

The following table summarizes the effects of a modifier applied to a called function. For every modifier, the table shows the order in which the function parameters are pushed on the stack. Next, the table shows whether the calling program (the caller) or the called function (the callee) is responsible for popping the parameters off the stack. Finally, the table shows the effect on the name of a global function.

Calling conventions

Modifier	Push parameters	Pop parameters	Name change (only in C)

__cdecl1	Right to left	Caller	'_' prepended

__fastcall	Left to right	Callee	'@' prepended

__pascal	Left to right	Callee	Uppercase

__stdcall	Right to left	Callee	No change

1. This is the default.

Note:	__fastcall and __stdcall are always name mangled in C++. See the description of the -VC option.


const

Syntax

const <variable name> [ = <value> ] ;

<function name> ( const <type>*<variable name> ;)

<function name> const;

Description

Use the const modifier to make a variable value unmodifiable.

Use the const modifier to assign an initial value to a variable that cannot be changed by the program. Any future assignments to a const result in a compiler error.

A const pointer cannot be modified, though the object to which it points can be changed. Consider the following examples.

   const float pi   = 3.14;

   const  maxint  = 12345;   // When used by itself, const is equivalent to int.

   char *const str1 = "Hello, world";           // A constant pointer

   char const *str2 = "Borland International";  // A pointer to a constant character string.

Given these declarations, the following statements are illegal.

pi   = 3.0;         // Assigns a value to a const.

i     = maxint++;   // Increments a const.

str1 = "Hi, there!" // Points str1 to something else.

Using the const Keyword in C++ Programs

C++ extends const to include classes and member functions. In a C++ class definition, use the const modifier following a member function declaration. The member function is prevented from modifying any data in the class.

A class object defined with the const keyword attempts to use only member functions that are also defined with const. If you call a member function that is not defined as const, the compiler issues a warning that a non-const function is being called for a const object. Using the const keyword in this manner is a safety feature of C++.

Warning:	A pointer can indirectly modify a const variable, as in the following:

*(int *)&maxint = 35;

If you use the const modifier with a pointer parameter in a function's parameter list, the function cannot modify the variable that the pointer points to. For example,

int printf (const char *format, ...);

printf is prevented from modifying the format string.


volatile

See also	Keywords

Syntax

volatile <data definition> ;

Description

Use the volatile modifier to indicate that a variable can be changed by a background routine, an interrupt routine, or an I/O port. Declaring an object to be volatile warns the compiler not to make assumptions concerning the value of the object while evaluating expressions in which it occurs because the value could change at any moment. It also prevents the compiler from making the variable a register variable

volatile int ticks;

void timer( ) {

   ticks++;

}

void wait (int interval) {

   ticks = 0;

   while (ticks < interval);  // Do nothing

}

The routines in this example (assuming timer has been properly associated with a hardware clock interrupt) implement a timed wait of ticks specified by the argument interval. A highly optimizing compiler might not load the value of ticks inside the test of the while loop since the loop doesn’t change the value of ticks.

Note:	C++ extends volatile to include classes and member functions. If you’ve declared a volatile object, you can use only its volatile member functions.


cdecl, _cdecl, and __cdecl
cdecl, _cdecl,  __cdecl

Example	Keywords

Syntax

cdecl <data/function definition> ;

_cdecl <data/function definition> ;

__cdecl <data/function definition> ;

Description

Use a cdecl, _cdecl, or __cdecl modifier to declare a variable or a function using the C-style naming conventions (case-sensitive, with a leading underscore appended). When you use cdecl, _cdecl, or __cdecl in front of a function, it effects how the parameters are passed (parameters pushed right to left, and the caller cleans up the stack). The __cdecl modifier overrides the compiler directives and IDE options.

The cdecl, _cdecl, and __cdecl keywords are specific to C++Builder.


pascal, _pascal, and __pascal
pascal, _pascal, __pascal

Keywords

Syntax

pascal <data-definition/function-definition> ;

_pascal <data-definition/function-definition> ;

__pascal <data-definition/function-definition> ;

Description

Use the pascal, _pascal, and __pascal keywords to declare a variable or a function using a Pascal-style naming convention (the name is in uppercase).

In addition, pascal declares Pascal-style parameter-passing conventions when applied to a function header (parameters pushed left to right; the called function cleans up the stack).

In C++ programs, functions declared with the pascal modifer will still be mangled.


_stdcall and __stdcall
_stdcall, __stdcall

Keywords

Syntax

__stdcall <function-name>

_stdcall <function-name>

Description

The _stdcall and __stdcall keywords force the compiler to generate function calls using the Standard calling convention. Functions must pass the correct number and type of arguments; this is unlike normal C use, which permits a variable number of function arguments. Such functions comply with the standard WIN32 argument-passing convention.


_fastcall and __fastcall
_fastcall, __fastcall

See also	Keywords

Syntax

return-value _fastcall function-name(parm-list)

return-value __fastcall function-name(parm-list)

Description

Use the __fastcall modifier to declare functions that expect parameters to be passed in registers. The first three parameters are passed (from left to right) in EAX, EDX, and ECX, if they fit in the register. The registers are not used if the parameter is a floating-point or struct type.

The compiler treats this calling convention as a new language specifier, along the lines of _cdecl and _pascal

Functions declared using _cdecl or _pascal cannot also have the _fastcall modifiers because they use the stack to pass parameters. Likewise, the __fastcall modifier cannot be used together with _export.

The compiler prefixes the __fastcall function name with an at-sign ("@"). This prefix applies to both unmangled C function names and to mangled C++ function names.


__thread, multithread variables

Keywords

Category

C++Builder keyword extensions

Description

The keyword __thread is used in multithread programs to preserve a unique copy of global and static class variables. Each program thread maintains a private copy of a __thread variable for each thread.

The syntax is Type __thread variable__name. For example

 int __thread x;

declares an integer type variable that will be global but private to each thread in the program in which the statement occurs.

The __thread modifier can be used with global (file-scope) and static variables. The modifier cannot be used with pointers or functions. (However, you can have pointers to __thread objects.) A program element that requires run-time initialization or run-time finalization cannot be declared to be a __thread type. The following declarations require run-time initialization and are therefore illegal.

int f( );

int __thread x = f( );   // illegal

Instantiation of a class with a user-defined constructor or destructor requires run-time initialization and is therefore illegal.

class X  {

   X( );

   ~X( );

};

X __thread myclass;   // illegal


Function modifiers

See also

This section presents descriptions of the C++Builder function modifiers

You can use the __export and __import modifiers to modify functions.

In 32-bit programs the keyword can be applied to class, function, and variable declarations

The __export modifier makes the function exportable from Windows. The __import modifier makes a function available to a Windows program. The keywords are used in an executable (if you don't use smart callbacks) or in a DLL.

Functions declared with the __fastcall modifier have different names than their non-__fastcall counterparts. The compiler prefixes the __fastcall function name with an @. This prefix applies to both unmangled C function names and to mangled C++ function names.

C++Builder modifiers

Modifier	Use with	Description

const1	Variables	Prevents changes to object.

volatile1	Variables	Prevents register allocation and some optimization. Warns compiler that object might be subject to outside change during evaluation.

__cdecl2	Functions	Forces C argument-passing convention. Affects linker and link-time names.

__cdecl2	Variables	Forces global identifier case-sensitivity and leading underscores in C.

__pascal	Functions	Forces Pascal argument-passing convention. Affects linker and link-time names.

__pascal	Variables	Forces global identifier case-insensitivity with no leading underscores in C.

__export	Functions/classes	Tells the compiler which functions or classes to export.

__import	Functions/classes	Tells the compiler which functions or classes to import.

__fastcall	Functions	Forces register parameter passing convention. Affects the linker and link-time names.

__stdcall	Function	Forces the standard WIN32 argument-passing convention.

1. C++ extends const and volatile to include classes and member functions.

2. This is the default.


Pointers

See also

Pointers fall into two main categories: pointers to objects and pointers to functions. Both types of pointers are special objects for holding memory addresses.

The two pointer classes have distinct properties, purposes, and rules for manipulation, although they do share certain C++Builder operations. Generally speaking, pointers to functions are used to access functions and to pass functions as arguments to other functions; performing arithmetic on pointers to functions is not allowed. Pointers to objects, on the other hand, are regularly incremented and decremented as you scan arrays or more complex data structures in memory.

Although pointers contain numbers with most of the characteristics of unsigned integers, they have their own rules and restrictions for assignments, conversions, and arithmetic. The examples in the next few sections illustrate these rules and restrictions.

Note:	See Referencing for a discussion of referencing and dereferencing.


Pointers to objects

See also

A pointer of type "pointer to object of type" holds the address of (that is, points to) an object of type. Since pointers are objects, you can have a pointer pointing to a pointer (and so on). Other objects commonly pointed at include arrays, structures, unions, and classes.


Pointers to functions

See also

A pointer to a function is best thought of as an address, usually in a code segment, where that function's executable code is stored; that is, the address to which control is transferred when that function is called.

A pointer to a function has a type called "pointer to function returning type," where type is the function's return type. For example,

void (*func)();

In C++, this is a pointer to a function taking no arguments, and returning void. In C, it's a pointer to a function taking an unspecified number of arguments and returning void. In this example,

void (*func)(int);

*func is a pointer to a function taking an int argument and returning void.

For C++, such a pointer can be used to access static member functions. Pointers to class members must use pointer-to-member operators. See static_cast for details.


Pointer declarations

See also

A pointer must be declared as pointing to some particular type, even if that type is void (which really means a pointer to anything). Once declared, though, a pointer can usually be reassigned so that it points to an object of another type. C++Builder lets you reassign pointers like this without typecasting, but the compiler will warn you unless the pointer was originally declared to be of type pointer to void. And in C, but not C++, you can assign a void* pointer to a non-void* pointer. See void for details.

Warning: You need to initialize pointers before using them.

If type is any predefined or user-defined type, including void, the declaration

type *ptr;   /* Uninitialized pointer */

declares ptr to be of type "pointer to type." All the scoping, duration, and visibility rules apply to the ptr object just declared.

A null pointer value is an address that is guaranteed to be different from any valid pointer in use in a program. Assigning the integer constant 0 to a pointer assigns a null pointer value to it.

The mnemonic NULL (defined in the standard library header files, such as stdio.h) can be used for legibility. All pointers can be successfully tested for equality or inequality to NULL.

The pointer type "pointer to void" must not be confused with the null pointer. The declaration

void *vptr;

declares that vptr is a generic pointer capable of being assigned to by any "pointer to type" value, including null, without complaint. Assignments without proper casting between a "pointer to type1" and a "pointer to type2," where type1 and type2 are different types, can invoke a compiler warning or error. If type1 is a function and type2 isn't (or vice versa), pointer assignments are illegal. If type1 is a pointer to void, no cast is needed. Under C, if type2 is a pointer to void, no cast is needed.


Pointer constants

See also

A pointer or the pointed-at object can be declared with the const modifier. Anything declared as a const cannot be have its value changed. It is also illegal to create a pointer that might violate the nonassignability of a constant object. Consider the following examples:

int i;                       // i is an int

int * pi;                    // pi is a pointer to int (uninitialized)

int * const cp = &i;         // cp is a constant pointer to int

const int ci = 7;            // ci is a constant int

const int * pci;             // pci is a pointer to constant int

const int * const cpc = &ci; // cpc is a constant pointer to a

                             // constant int

The following assignments are legal:

i = ci;                     // Assign const-int to int

*cp = ci;                   // Assign const-int to

                            // object-pointed-at-by-a-const-pointer

++pci;                      // Increment a pointer-to-const

pci = cpc;                  // Assign a const-pointer-to-a-const to a

                            // pointer-to-const

The following assignments are illegal:

ci = 0;                     // NO--cannot assign to a const-int

ci--;                       // NO--cannot change a const-int

*pci = 3;                   // NO--cannot assign to an object

                            // pointed at by pointer-to-const

cp = &ci;                   // NO--cannot assign to a const-pointer,

                            // even if value would be unchanged

cpc++;                      // NO--cannot change const-pointer

pi = pci;                   // NO--if this assignment were allowed,

                            // you would be able to assign to *pci

                            // (a const value) by assigning to *pi.

Similar rules apply to the volatile modifier. Note that const and volatile can both appear as modifiers to the same identifier.


Pointer arithmetic

See also

Pointer arithmetic is limited to addition, subtraction, and comparison. Arithmetical operations on object pointers of type "pointer to type" automatically take into account the size of type; that is, the number of bytes needed to store a type object.

The internal arithmetic performed on pointers depends on the memory model in force and the presence of any overriding pointer modifiers.

When performing arithmetic with pointers, it is assumed that the pointer points to an array of objects. Thus, if a pointer is declared to point to type, adding an integral value to the pointer advances the pointer by that number of objects of type. If type has size 10 bytes, then adding an integer 5 to a pointer to type advances the pointer 50 bytes in memory. The difference has as its value the number of array elements separating the two pointer values. For example, if ptr1 points to the third element of an array, and ptr2 points to the tenth element, then the result of ptr2 - ptr1 would be 7.

The difference between two pointers has meaning only if both pointers point into the same array

When an integral value is added to or subtracted from a "pointer to type," the result is also of type "pointer to type."

There is no such element as "one past the last element," of course, but a pointer is allowed to assume such a value. If P points to the last array element, P + 1 is legal, but
P + 2 is undefined. If P points to one past the last array element, P - 1 is legal, giving a pointer to the last element. However, applying the indirection operator * to a "pointer to one past the last element" leads to undefined behavior.

Informally, you can think of P + n as advancing the pointer by (n * sizeof(type)) bytes, as long as the pointer remains within the legal range (first element to one beyond the last element).

Subtracting two pointers to elements of the same array object gives an integral value of type ptrdiff_t defined in stddef.h. This value represents the difference between the subscripts of the two referenced elements, provided it is in the range of ptrdiff_t. In the expression P1 - P2, where P1 and P2 are of type pointer to type (or pointer to qualified type), P1 and P2 must point to existing elements or to one past the last element. If P1 points to the i-th element, and P2 points to the j-th element, P1 - P2 has the value (i - j).


Pointer conversions

See also

Pointer types can be converted to other pointer types using the typecasting mechanism:

char *str;

int *ip;

str = (char *)ip;

More generally, the cast (type*) will convert a pointer to type "pointer to type."
See C++ specific for a discussion of C++ typecast mechanisms.


C++ reference declarations

See also

C++ reference types are closely related to pointer types. Reference types create aliases for objects and let you pass arguments to functions by reference. C passes arguments only by value. In C++ you can pass arguments by value or by reference. See Referencing for complete details.


Arrays

See also

The declaration

type declarator [<constant-expression>]

declares an array composed of elements of type. An array consists of a contiguous region of storage exactly large enough to hold all of its elements.

If an expression is given in an array declarator, it must evaluate to a positive constant integer. The value is the number of elements in the array. Each of the elements of an array is numbered from 0 through the number of elements minus one.

Multidimensional arrays are constructed by declaring arrays of array type. The following example shows one way to declare a two-dimensional array. The implementation is for three rows and five columns but it can be very easily modified to accept run-time user input.

/* DYNAMIC MEMORY ALLOCATION FOR A MULTIDIMENSIONAL OBJECT. */

#include <stdio.h>

#include <stdlib.h>

typedef long double TYPE;

typedef TYPE *OBJECT;

unsigned int rows = 3, columns = 5;

void de_allocate(OBJECT);

int main(void) {

  OBJECT matrix;

  unsigned int i, j;

  /* STEP 1: SET UP THE ROWS. */

  matrix = (OBJECT) calloc( rows, sizeof(TYPE *));

  /* STEP 2: SET UP THE COLUMNS. */

  for (i = 0; i < rows; ++i)

    matrix[i] = (TYPE *) calloc( columns, sizeof(TYPE));

    for (i = 0; i < rows; i++)

      for (j = 0; j < columns; j++)

        matrix[i][j] = i + j;    /* INITIALIZE */

  for (i = 0; i < rows; ++i) {

    printf("\n\n");

    for (j = 0; j < columns; ++j)

      printf("%5.2Lf", matrix[i][j]);

  de_allocate(matrix);

  return 0;

  }

void de_allocate(OBJECT x) {

  int i;

  for (i = 0; i < rows; i++)    /* STEP 1: DELETE THE COLUMNS */

    free(x[i]);

  free(x);    /* STEP 2: DELETE THE ROWS. */

  }

This code produces the following output:

0.00 1.00 2.00 3.00 4.00

1.00 2.00 3.00 4.00 5.00

2.00 3.00 4.00 5.00 6.00

In certain contexts, the first array declarator of a series might have no expression inside the brackets. Such an array is of indeterminate size. This is legitimate in contexts where the size of the array is not needed to reserve space.

For example, an extern declaration of an array object does not need the exact dimension of the array; neither does an array function parameter. As a special extension to ANSI C, C++Builder also allows an array of indeterminate size as the final member of a structure. Such an array does not increase the size of the structure, except that padding can be added to ensure that the array is properly aligned. These structures are normally used in dynamic allocation, and the size of the actual array needed must be explicitly added to the size of the structure in order to properly reserve space.

Except when it is the operand of a sizeof or & operator, an array type expression is converted to a pointer to the first element of the array.


Functions

See also

Functions are central to C and C++ programming. Languages such as Pascal distinguish between procedure and function. For C and C++, functions play both roles.

Member functions are sometimes referred to as methods.


Declarations and definitions

See also

Each program must have a single external function named main or WinMain marking the entry point of the program. Functions are usually declared as prototypes in standard or user-supplied header files, or within program files. Functions are external by default and are normally accessible from any file in the program. They can be restricted by using the static storage class specifier (see Linkage).

Functions are defined in your source files or made available by linking precompiled libraries.

A given function can be declared several times in a program, provided the declarations are compatible. Nondefining function declarations using the function prototype format provide C++Builder with detailed parameter information, allowing better control over argument number and type checking, and type conversions.

Note:	In C++ you must always use function prototypes. We recommend that you also use them in C.

Excluding C++ function overloading, only one definition of any given function is allowed. The declarations, if any, must also match this definition. (The essential difference between a definition and a declaration is that the definition has a function body.


Declarations and prototypes

See also

In the Kernighan and Ritchie style of declaration, a function could be implicitly declared by its appearance in a function call, or explicitly declared as follows

<type> func()

where type is the optional return type defaulting to int. In C++, this declaration means <type> func(void). A function can be declared to return any type except an array or function type. This approach does not allow the compiler to check that the type or number of arguments used in a function call match the declaration.

This problem was eased by the introduction of function prototypes with the following declaration syntax:

<type> func(parameter-declarator-list);

Note:	You can enable a warning  with the command-line compiler: "Function called without a prototype."

Declarators specify the type of each function parameter. The compiler uses this information to check function calls for validity. The compiler is also able to coerce arguments to the proper type. Suppose you have the following code fragment:

extern long lmax(long v1, long v2); /* prototype */

foo()

{

   int limit = 32;

   char ch = 'A';

   long mval;

   mval = lmax(limit,ch);    /* function call */

}

Since it has the function prototype for lmax, this program converts limit and ch to long, using the standard rules of assignment, before it places them on the stack for the call to lmax. Without the function prototype, limit and ch would have been placed on the stack as an integer and a character, respectively; in that case, the stack passed to lmax would not match in size or content what lmax was expecting, leading to problems. The classic declaration style does not allow any checking of parameter type or number, so using function prototypes aids greatly in tracking down programming errors.

Function prototypes also aid in documenting code. For example, the function strcpy takes two parameters: a source string and a destination string. The question is, which is which? The function prototype

char *strcpy(char *dest, const char *source);

makes it clear. If a header file contains function prototypes, then you can print that file to get most of the information you need for writing programs that call those functions. If you include an identifier in a prototype parameter, it is used only for any later error messages involving that parameter; it has no other effect.

A function declarator with parentheses containing the single word void indicates a function that takes no arguments at all:

func(void);

In C++, func() also declares a function taking no arguments

A function prototype normally declares a function as accepting a fixed number of parameters. For functions that accept a variable number of parameters (such as printf), a function prototype can end with an ellipsis (...), like this:

f(int *count, long total, ...)

With this form of prototype, the fixed parameters are checked at compile time, and the variable parameters are passed with no type checking.

Note:	stdarg.h and varargs.h contain macros that you can use in user-defined functions with variable numbers of parameters.

Here are some more examples of function declarators and prototypes:

int  f();	/* In C, a function returning an int with	 no information about parameters.

This is the K&R "classic style." */

int f();	/* In C++, a function taking no arguments */

int  f(void);	/* A function returning an int that takes	 	no parameters. */

int  p(int,long);	/* A function returning an int that
accepts two parameters: the first,
 an int; the second, a long. */

int  __pascal q(void);	/* A pascal function returning
an int that takes no parameters at all. */

int  printf(char *format,...;  /*	A function returning an int and
accepting a pointer to a char fixed
parameter and any number of additional
parameters of unknown type. */

int  (*fp)(int)	/* A pointer to a function returning an int
and requiring an int parameter. */


Definitions

See also

The general syntax for external function definitions is as follows:

External function definitions

file

external-definition

file  external-definition

external-definition:

function-definition

declaration

asm-statement

function-definition:

<declaration-specifiers> declarator <declaration-list>

compound-statement

In general, a function definition consists of the following sections (the grammar allows for more complicated cases):

1.	Optional storage class specifiers: extern or static. The default is extern.

2.	A return type, possibly void. The default is int.

3.	Optional modifiers: __pascal, __cdecl,  __export. The defaults depend on the compiler option settings.

4.	The name of the function.

5.	A parameter declaration list, possibly empty, enclosed in parentheses. In C, the preferred way of showing an empty list is func(void). The old style of func is legal in C but antiquated and possibly unsafe.

6.	A function body representing the code to be executed when the function is called.

Note:	You can mix elements from 1 and 2.


Formal parameter declarations

See also

The formal parameter declaration list follows a syntax similar to that of the declarators found in normal identifier declarations. Here are a few examples:

int func(void) {                   // no args

int func(T1 t1, T2 t2, T3 t3=1) {  // three simple parameters, one

                                   // with default argument

int func(T1* ptr1, T2& tref) {     // A pointer and a reference arg

int func(register int i) {         // Request register for arg

int func(char *str,...) {          /* One string arg with a variable number of other

                               args, or with a fixed number of args with varying types */

In C++, you can give default arguments as shown. Parameters with default values must be the last arguments in the parameter list. The arguments' types can be scalars, structures, unions, or enumerations; pointers or references to structures and unions; or pointers to functions,  classes, or arrays.

The ellipsis (...) indicates that the function will be called with different sets of arguments on different occasions. The ellipsis can follow a sublist of known argument declarations. This form of prototype reduces the amount of checking the compiler can make.

The parameters declared all have automatic scope and duration for the duration of the function. The only legal storage class specifier is register.

The const and volatile modifiers can be used with formal parameter declarators


Function calls and argument conversions

See also

A function is called with actual arguments placed in the same sequence as their matching formal parameters. The actual arguments are converted as if by initialization to the declared types of the formal parameters.

Here is a summary of the rules governing how C++Builder deals with language modifiers and formal parameters in function calls, both with and without prototypes:

 	The language modifiers for a function definition must match the modifiers used in the declaration of the function at all calls to the function.

 	A function can modify the values of its formal parameters, but this has no effect on the actual arguments in the calling routine, except for reference arguments in C++.

When a function prototype has not been previously declared, C++Builder converts integral arguments to a function call according to the integral widening (expansion) rules described in Standard arithmetic conversions. When a function prototype is in scope, C++Builder converts the given argument to the type of the declared parameter as if by assignment

When a function prototype includes an ellipsis (...), C++Builder converts all given function arguments as in any other prototype (up to the ellipsis). The compiler widens any arguments given beyond the fixed parameters, according to the normal rules for function arguments without prototypes.

If a prototype is present, the number of arguments must match (unless an ellipsis is present in the prototype). The types need to be compatible only to the extent that an assignment can legally convert them. You can always use an explicit cast to convert an argument to a type that is acceptable to a function prototype.

Note:	If your function prototype does not match the actual function definition, C++Builder will detect this if and only if that definition is in the same compilation unit as the prototype. If you create a library of routines with a corresponding header file of prototypes, consider including that header file when you compile the library, so that any discrepancies between the prototypes and the actual definitions will be caught.
C++ provides type-safe linkage, so differences between expected and actual parameters will be caught by the linker.


Structures

See also

A structure is a derived type usually representing a user-defined collection of named members (or components). The members can be of any type, either fundamental or derived (with some restrictions to be noted later), in any sequence. In addition, a structure member can be a bit field type not allowed elsewhere. The C++Builder structure type lets you handle complex data structures almost as easily as single variables. Structure initialization is discussed in Arrays, structures, and unions.

In C++, a structure type is treated as a class type with certain differences: default access is public, and the default for the base class is also public. This allows more sophisticated control over access to structure members by using the C++ access specifiers: public (the default), private, and protected. Apart from these optional access mechanisms, and from exceptions as noted, the following discussion on structure syntax and usage applies equally to C and C++ structures.

Structures are declared using the keyword struct. For example

struct mystruct { ... }; // mystruct is the structure tag

    .

    .

    .

struct mystruct s, *ps, arrs[10];

/* s is type struct mystruct; ps is type pointer to struct mystruct;

   arrs is array of struct mystruct. */


Untagged structures and typedefs

See also

If you omit the structure tag, you can get an untagged structure. You can use untagged structures to declare the identifiers in the comma-delimited struct-id-list to be of the given structure type (or derived from it), but you cannot declare additional objects of this type elsewhere

struct { ... } s, *ps, arrs[10]; // untagged structure

It is possible to create a typedef while declaring a structure, with or without a tag:

typedef struct mystruct { ... } MYSTRUCT;

MYSTRUCT s, *ps, arrs[10];       // same as struct mystruct s, etc.

typedef struct { ... } YRSTRUCT; // no tag

YRSTRUCT y, *yp, arry[20];

Usually, you don't need both a tag and a typedef: either can be used in structure declarations.

Untagged structure and union members are ignored during initialization.


Anonymous structures
Unnamed and anonymous structures (C and C++)

See also

ANSI C++ allows only unnamed anonymous structures that declare an object. ANSI C does not allow anonymous structure objects. Borland C and C++ allow various types of anonymous structures that extend ANSI.

Nested anonymous structures

Borland C and C++ allow anonymous structures that do not have a tag and that are not used to declare an object (or other type). These structures have the following form:

struct { member-list };

Anonymous structures must be nested, that is, declared within another struct, a union, or, (in C++ only) a class. For example:

struct my_struct {

  int x;

  struct {  // anonymous struct nested inside of my_struct

    int i;

  };

  inline int func1(int y);

} S;

The outer structure must be a named type, that is, it must have either a tag or a named object.

Because there is no instance variable, the C++ syntax for anonymous structures cannot reference a C++ this pointer. Therefore, whereas a C++ structure can typically have member functions, C++ anonymous structures cannot. Data members of anonymous structures can be accessed directly in the scope where this structure is declared, without using the x.y or p->y syntax. For example:

struct my_struct{

  int x;

  struct{

    int i;

  };

  inline int func1(int y){return y + i + x;}

} S;

int main()

{

  S.x = 6;

  S.i = 4;

  int y = S.func1(3);

  printf(“y is %d“, y);

  return 0;

}

anonymous structures

For Microsoft compatibility, a Borland C extension allows you to declare a tagged struct that does not declare an object. These anonymous structures must be used nested. For example:

struct address

{

  char street[25];

  int st_number;

];

struct person

{

  char name[35]

  struct address;	//anonmymous structure

} candidate;

candidate.st_number = 10;


Structure member declarations

See also

The member-decl-list within the braces declares the types and names of the structure members using the declarator syntax shown in C++Builder declaration syntax.

A structure member can be of any type, with two exceptions

 	The member type cannot be the same as the struct type being currently declared:

struct mystruct { mystruct s } s1, s2; // illegal

However, a member can be a pointer to the structure being declared, as in the following example:

struct mystruct { mystruct *ps } s1, s2; // OK

Also, a structure can contain previously defined structure types when declaring an instance of a declared structure.

 	Except in C++, a member cannot have the type "function returning...," but the type "pointer to function returning..." is allowed. In C++, a struct can have member functions.

Note:	You can omit the struct keyword in C++.


Structures and functions

See also

A function can return a structure type or a pointer to a structure type:

mystruct func1(void);  // func1() returns a structure

mystruct *func2(void); // func2() returns pointer to structure

A structure can be passed as an argument to a function in the following ways:

void func1(mystruct s);        // directly

void func2(mystruct *sptr);    // via a pointer

void func3(mystruct &sref);    // as a reference (C++ only)


Structure member access

See also

Structure and union members are accessed using the following two selection operators:

. (period)

-> (right arrow)

Suppose that the object s is of struct type S, and sptr is a pointer to S. Then if m is a member identifier of type M declared in S, the expressions s.m and sptr->m are of type M, and both represent the member object m in S. The expression sptr->m is a convenient synonym for (*sptr).m.

The operator . is called the direct member selector and the operator -> is called the indirect (or pointer) member selector. For example:

struct mystruct

{

   int i;

   char str[21];

   double d;

} s, *sptr = &s;

    .

    .

    .

s.i = 3;            // assign to the i member of mystruct s

sptr -> d = 1.23;   // assign to the d member of mystruct s

The expression s.m is an lvalue, provided that s is an lvalue and m is not an array type. The expression sptr->m is an lvalue unless m is an array type.

If structure B contains a field whose type is structure A, the members of A can be accessed by two applications of the member selectors

struct A {

   int j;

   double x;

};

struct B {

   int i;

   struct A a;

   double d;

} s, *sptr;

    .

    .

    .

s.i = 3;            // assign to the i member of B

s.a.j = 2;          // assign to the j member of A

sptr->d = 1.23;     // assign to the d member of B

sptr->a.x = 3.14  // assign to x member of A

Each structure declaration introduces a unique structure type, so that in

struct A {

   int i,j;

   double d;

} a, a1;

struct B {

   int i,j;

   double d;

} b;

the objects a and a1 are both of type struct A, but the objects a and b are of different structure types. Structures can be assigned only if the source and destination have the same type:

a = a1;   // OK: same type, so member by member assignment

a = b;    // ILLEGAL: different types

a.i = b.i; a.j = b.j; a.d = b.d /* but you can assign member-by-member */


Structure name spaces

See also

Structure tag names share the same name space with union tags and enumeration tags (but enums within a structure are in a different name space in C++). This means that such tags must be uniquely named within the same scope. However, tag names need not differ from identifiers in the other three name spaces: the label name space, the member name space(s), and the single name space (which consists of variables, functions, typedef names, and enumerators).

Member names within a given structure or union must be unique, but they can share the names of members in other structures or unions. For example

goto s;

    .

    .

    .

s:           // Label

struct s {   // OK: tag and label name spaces different

   int s;    // OK: label, tag and member name spaces different

   float s;  // ILLEGAL: member name duplicated

} s;         // OK: var name space different. In C++, this can only

             // be done if s does not have a constructor.

union s {    // ILLEGAL: tag space duplicate

   int s;    // OK: new member space

   float f;

} f;         // OK: var name space

struct t {

   int s;    // OK: different member space

    .

    .

    .

} s;         // ILLEGAL: var name duplicate


Incomplete declarations

See also

Incomplete declarations are also known as forward declarations.

A pointer to a structure type A can legally appear in the declaration of another structure B before A has been declared:

struct A;                  // incomplete

struct B { struct A *pa };

struct A { struct B *pb };

The first appearance of A is called incomplete because there is no definition for it at that point. An incomplete declaration is allowed here, because the definition of B doesn't need the size of A.


Bit fields

See also

Bit fields are specififed numbers of bits that may or may not have an associated identifier. Bit fields offer a way of sub-dividing structures (structs, unions, classes) into named parts of user-defined sizes.

Declaring bit fields

You specify the bit-field width and optional identifier as follows:

type-specifier <bitfield-id> : width;

In C++, type-specifier  is bool, char, unsigned char, short, unsigned short, long, unsigned long, int, unsigned int, __int64 or unsigned __int64. In strict ANSI C, type-specifier is int or unsigned int.

The expression width must be present and must evaluate to a constant integer. In C++ , the width of a bit field may be declared of any size. In strict ANSI C, the width of a bit field may be declared only up to the size of the declared type. A zero length bit field skips to the next allocation unit.

If the bit field identifier is omitted, the number of bits specified in width is allocated, but the field is not accessible. This lets you match bit patterns in, say, hardware registers where some bits are unused.

Bit fields can be declared only in structures, unions, and classes. They are accessed with the same member selectors ( . and ->) used for non-bit-field members.

Limitations of using bit fields

When using bit fields, be aware of the following issues:

•	the code will be non-portable since the organization of bits-within-bytes and bytes-within-words is machine dependent.

•	you cannot take the address of a bit field; so the expression &mystruct.x is illegal if x is a bit field identifier, because there is no guarantee that mystruct.x lies at a byte address.

•	bit fields are used to pack more variables into a smaller data space, but causes the compiler to generate additional code to manipulate these variables. This costs in terms of code size and execution time.

Because of these disadvantages, using bit fields is generally discouraged, except for certain low level programming. A recommended alternative to having one bit variables, or flags, is to use defines. For example:

#define Nothing	0x00

#define bitOne	0x01

#define bitTwo	0x02

#define bitThree	0x04

#define bitFour	0x08

#define bitFive	0x10

#define bitSix	0x20

#define bitSeven	0x40

#define bitEight	0x80

can be used to write code like:

if (flags & bitOne) {...}    // is bit One turned on

flags |= bitTwo;               // turn bit Two on

flags &= ~bitThree;         // turn bit Three off

Similar schemes can be made for bit fields of any size.

Padding of bit fields

In C++ , if the width size is larger than the type of the bit field, the compiler will insert padding equal to the requested width size minus the size of the type of the bit field. So, declaration:

struct mystruct

{

  int i : 40;

  int j : 8;

};

will create a 32 bit storage for 'i', an 8 bit padding, and 8 bit storage for 'j'. To optimize access, the compiler will consider 'i' to be a regular int variable, not a bit field.

Layout and alignment

Bit fields are broken up into groups of consecutive bit fields of the same type, without regard to signedness. Each group of bit fields is aligned to the current alignment of the type of the members of the group. This alignment is determined by the type AND by the setting of the overall alignment (set by the byte alignment option –aN). Within each group, the compiler will pack the bit fields inside of areas as large as the type size of the bit fields. However, no bit field is allowed to straddle the boundary between 2 of those areas. The size of the total structure will be aligned, as determined by the current alignment.

Example of bit field layout, padding, and alignment

In the following C++ declaration, my_struct contains 6 bit fields of 3 different types, int, long, and char:

struct my_struct

{

   int one : 8;

   unsigned int two : 16;

   unsigned long three : 8;

   long four : 16;

   long five : 16;

   char six : 4;

};

Bit fields 'one' and 'two' will be packed into one 32 bit area.

Next, the compiler inserts padding, if necessary, based on the current alignment, and the type of three, because the type changes between the declarations of variables two and three. For example, if the current alignment is byte alignment (-a1), no padding is needed; whereas, if the alignment is 4 bytes (-a4), then 8 bit padding is inserted.

Next, variables three, four, and five are all of type long. Variables three and four are packed into one 32 bit area, but five can not be packed into that same area, since that would create an area of 40 bits, which is more than the 32 bit allowed for the long type. To start a new area for five, the compiler would insert no padding if the current alignment is byte alignment, or would insert 8 bits of padding if the current alignment is dword (4 byte) alignment.

With variable six, the type changes again. Since char is always byte aligned, no padding is needed. To force alignment for the whole struct, the compiler will finish up the last area with 4 bits of padding if byte alignment is used, or 12 bits of padding if dword alignment is used.

The total size of my_struct is 9 bytes with byte alignment, or 12 bytes with dword alignment.

To get the best results when using bit fields you should:

•	sort bit fields by type

•	make sure they are packed inside the areas by ordering them such that no bit field will straddle an area boundary

•	make sure the struct is filled as much as possible.

Another recommendation is to force byte alignment for this struct, by emitting "#pragma option -a1". If you want to know how big your struct is, follow it by "#pragma sizeof(mystruct)", which  gives you the size.

Using one bit signed fields

For a signed type of one bit, the possible values are 0 or –1. For an unsigned type of one bit, the possible values are 0 or 1. Note that if you assign “1” to a signed bit field, the value will be evaluated as –1 (negative one).

When storing the values true and false into a one bit sized bit field of a signed type, you can not test for equality to true because signed one bit sized bit fields can only hold the values '0' and '-1', which are not compatible with true and false. You can, however, test for non-zero.

For unsigned varieties of all types, and of course for the bool type, testing for equality to true will work as expected.

Thus:

struct mystruct

{

   int flag : 1;

} M;

int testing() { M.flag = true; if (M.flag == true) printf("success");}

will NOT work, but:

struct mystruct

{

   int flag : 1;

} M;

int testing() { M.flag = true; if (M.flag) printf("success");}

will work just fine.

Notes on compatibility

Between versions of the compiler, changes can be made to default alignment, or for purposes of compatibility with other compilers. Consequently, this could change the alignment of bit fields. Therefore, there is no guarantee that the alignment of bit fields will be consistent between versions of the C++Builder compiler. To check the backward compatibility of bit fields in your code you can add an assert that checks for the structure size you are expecting.

According to the C and C++ language specifications, the alignment and storage of bit fields is implementation defined. Therefore, compilers can align and store bit fields differently. If you want complete control over the layout of bit fields, it is advisable to write your own bit field accessing routines and create your own bit fields.


Unions

See also

Union types are derived types sharing many of the syntactical and functional features of structure types. The key difference is that a union allows only one of its members to be "active" at any one time. The size of a union is the size of its largest member. The value of only one of its members can be stored at any time. In the following simple case,

union myunion {     /* union tag = myunion */

   int i;

   double d;

   char ch;

} mu, *muptr=&mu;

the identifier mu, of type union myunion, can be used to hold an int, an 8-byte double, or a single-byte char, but only one of these at the same time

Note:	Unions correspond to the variant record types of Pascal and Modula-2.

sizeof(union myunion) and sizeof(mu) both return 8, but 4 bytes are unused (padded) when mu holds an int object, and 7 bytes are unused when mu holds a char. You access union members with the structure member selectors (. and ->), but care is needed:

mu.d = 4.016;

printf("mu.d = %f\n",mu.d); //OK: displays mu.d = 4.016
printf("mu.i = %d\n",mu.i); //peculiar result
mu.ch = 'A';

printf("mu.ch = %c\n",mu.ch); //OK: displays mu.ch = A
printf("mu.d = %f\n",mu.d); //peculiar result
muptr->i = 3;

printf("mu.i = %d\n",mu.i); //OK: displays mu.i = 3

The second printf is legal, since mu.i is an integer type. However, the bit pattern in mu.i corresponds to parts of the double previously assigned, and will not usually provide a useful integer interpretation.

When properly converted, a pointer to a union points to each of its members, and vice versa.


Anonymous unions
Anonymous unions (C and C++)

See also

A union that does not have a tag and is not used to declare a named object (or other type) is called an anonymous union. It has the following form:

union { member-list };

Its members can be accessed directly in the scope where this union is declared, without using the x.y or p->y syntax.

Anonymous unions can be global, nested, or unnested. ANSI-C never allows anonymous unions. ANSI-C++ allows all three types of anonymous unions.

C++ Anonymous unions

An anonymous union cannot have member functions or private or protected members. At file level an anonymous union must be declared static. Local anonymous unions must be either automatic or static; in other words, an anonymous union cannot have external linkage. Unnested anonymous unions are only allowed in C++.

Nested anonymous unions

The outer structure, class, or union of a nested anonymous union must have a tag. Borland C and C++ allow nested anonymous unions by default. In C only, a nested anonymous union can, optionally, have a tag.

Example:

struct outer {

        int x;

        union {

                int y;

                char c;

        };

};

int main(void)

{

        struct outer o;

        return o.x + o.y;

}


Union declarations

See also

The general declaration syntax for unions is similar to that for structures. The differences are:

 	Unions can contain bit fields, but only one can be active. They all start at the beginning of the union. (Note that, because bit fields are machine dependent, they can pose problems when writing portable code.)

 	Unlike C++ structures, C++ union types cannot use the class access specifiers: public, private, and protected. All fields of a union are public.

 	Unions can be initialized only through their first declared member:

union local87 {

   int i;

   double d;

   } a = { 20 };

 	A union can't participate in a class hierarchy. It can't be derived from any class, nor can it be a base class. A union can have a constructor.


Enumerations

See also

An enumeration data type is used to provide mnemonic identifiers for a set of integer values. For example, the following declaration:

enum days { sun, mon, tues, wed, thur, fri, sat } anyday;

establishes a unique integral type, enum days, a variable anyday of this type, and a set of enumerators (sun, mon,...) with constant integer values.

The -b compiler switch controls the “Treat Enums As Ints” option. When this switch is used, the compiler allocates a whole word (a four-byte int) for enumeration types (variables of type enum). The default is ON (meaning enums are always ints) if the range of values permits, but the value is always promoted to an int when used in expressions. The identifiers used in an enumerator list are implicitly of type signed char, unsigned char, or int, depending on the values of the enumerators. If all values can be represented in a signed or unsigned char, that is the type of each enumerator.

In C, a variable of an enumerated type can be assigned any value of type int--no type checking beyond that is enforced. In C++, a variable of an enumerated type can be assigned only one of its enumerators. That is:

anyday = mon;       // OK

anyday = 1;         // illegal, even though mon == 1

The identifier days is the optional enumeration tag that can be used in subsequent declarations of enumeration variables of type enum days:

enum days payday, holiday; // declare two variables

In C++, you can omit the enum keyword if days is not the name of anything else in the same scope.

As with struct and union declarations, you can omit the tag if no further variables of this enum type are required:

enum { sun, mon, tues, wed, thur, fri, sat } anyday;

/* anonymous enum type */

The enumerators listed inside the braces are also known as enumeration constants. Each is assigned a fixed integral value. In the absence of explicit initializers, the first enumerator (sun) is set to zero, and each succeeding enumerator is set to one more than its predecessor (mon = 1, tues = 2, and so on). See Enumeration constants for more on enumeration constants.

With explicit integral initializers, you can set one or more enumerators to specific values. Any subsequent names without initializers will then increase by one. For example, in the following declaration:

/* Initializer expression can include previously declared enumerators */

enum coins { penny = 1, tuppence, nickel = penny + 4, dime = 10,

             quarter = nickel * nickel } smallchange;

tuppence would acquire the value 2, nickel the value 5, and quarter the value 25.

The initializer can be any expression yielding a positive or negative integer value (after possible integer promotions). These values are usually unique, but duplicates are legal.

enum types can appear wherever int types are permitted.

enum days { sun, mon, tues, wed, thur, fri, sat } anyday;

enum days payday;

typedef enum days DAYS;

DAYS *daysptr;

int i = tues;

anyday = mon;        // OK

*daysptr = anyday;   // OK

mon = tues;          // ILLEGAL: mon is a constant

Enumeration tags share the same name space as structure and union tags. Enumerators share the same name space as ordinary variable identifiers:

int mon = 11;

{

   enum days { sun, mon, tues, wed, thur, fri, sat } anyday;

   /* enumerator mon hides outer declaration of int mon */

   struct days { int i, j;};   // ILLEGAL: days duplicate tag

   double sat;                 // ILLEGAL: redefinition of sat

}

mon = 12;                      // back in int mon scope

In C++, enumerators declared within a class are in the scope of that class.

In C++ it is possible to overload most operators for an enumeration. However, because the =, [ ], ( ), and -> operators must be overloaded as member functions, it is not possible to overload them for an enum. See the example on how to overload the postfix and prefix increment operators.


How to overload enum operators

   // OVERLOAD THE POSTFIX AND PREFIX INCREMENT OPERATORS FOR enum

   #include <iostream.h>

   enum _SEASON { spring, summer, fall, winter };

   _SEASON operator++(_SEASON &s) {      // PREFIX INCREMENT

      // DO MODULAR ARITHMETIC AND CAST THE RESULT TO _SEASON TYPE

      s = _SEASON( (s + 1) % 4 );        // INCREMENT THE ORIGINAL

      return s;                          // RETURN THE NEW VALUE

      }

   // UNNAMED int ARGUMENT IS NOT USED

   _SEASON operator++(_SEASON &s, int) { // POSTFIX INCREMENT

      _SEASON tmp = s;

      switch (s) {

         case spring: s = summer; break;

         case summer: s = fall; break;

         case fall:   s = winter; break;

         case winter: s = spring; break;

         }

      return (tmp);

      }

   int main(void) {

      _SEASON season = fall;

      cout << "\nThe season is " << season;

      cout << "\nIncrement the season: "<< ++season;

      cout << "\nNo change yet when using postfix: " << season++;

      cout << "\nFinally:" << season;

      return 0;

      }

This code produces the following output:

The season is 2

Increment the season: 3

No change yet when using postfix: 3

Finally:0


Assignment to enum types

The rules for expressions involving enum types have been made stricter. The compiler enforces these rules with error messages if the compiler switch -A is turned on (which means strict ANSI C++).

Assigning an integer to a variable of enum type results in an error:

enum color

{

  red, green, blue

};

int f()

{

  color c;

  c = 0;

  return c;

}

The same applies when passing an integer as a parameter to a function. Notice that the result type of the expression flag1|flag2 is int:

enum e

{

  flag1 = 0x01,

  flag2 = 0x02

};

void p(e);

void f()

{

  p(flag1|flag2);

}

To make the example compile, the expression flag1|flag2 must be cast to the enum type: e (flag1|flag2).


Expressions

See also

An expression is a sequence of operators, operands, and punctuators that specifies a computation. The formal syntax, listed in C++Builder expressions, indicates that expressions are defined recursively: subexpressions can be nested without formal limit. (However, the compiler will report an out-of-memory error if it can't compile an expression that is too complex.)

Note:	C++Builder expressions shows how identifiers and operators are combined to form grammatically legal "phrases."

Expressions are evaluated according to certain conversion, grouping, associativity, and precedence rules that depend on the operators used, the presence of parentheses, and the data types of the operands.The standard conversions are detailed in Methods used in standard arithmetic conversions. The way operands and subexpressions are grouped does not necessarily specify the actual order in which they are evaluated by C++Builder (see Evaluation order).

Expressions can produce an lvalue, an rvalue, or no value. Expressions might cause side effects whether they produce a value or not

The precedence and associativity of the operators are summarized in Associativity and precedence of C++Builder operators. The grammar in C++Builder expressions, completely defines the precedence and associativity of the operators

C++Builder expressions

primary-expression:

literal

this (C++ specific)

:: identifier (C++ specific)

:: operator-function-name (C++ specific)

:: qualified-name (C++ specific)

(expression)

name

literal:

integer-constant

character-constant

floating-constant

string-literal

name:

identifier

operator-function-name (C++ specific)

conversion-function-name (C++ specific)

~ class-name (C++ specific)

qualified-name (C++ specific)

qualified-name: (C++ specific)

qualified-class-name :: name

postfix-expression:

primary-expression

postfix-expression  [ expression ]

postfix-expression  ( <expression-list> )

simple-type-name    ( <expression-list> ) (C++ specific)

postfix-expression  .  name

postfix-expression  ->  name

postfix-expression  ++

postfix-expression  --

const_cast < type-id > ( expression ) (C++ specific)

dynamic_cast < type-id > ( expression ) (C++ specific)

reinterpret_cast < type-id > ( expression ) (C++ specific)

static_cast < type-id > ( expression ) (C++ specific)

typeid ( expression ) (C++ specific)

typeid ( type-name ) (C++ specific)

expression-list:

assignment-expression

expression-list  ,  assignment-expression

unary-expression:

postfix-expression

++ unary-expression

- - unary-expression

unary-operator  cast-expression

sizeof unary-expression

sizeof ( type-name )

allocation-expression (C++ specific)

deallocation-expression (C++ specific)

unary-operator: one of & * + - !

allocation-expression: (C++ specific)

<::> new <placement> new-type-name <initializer>

<::> new <placement> (type-name) <initializer>

placement: (C++ specific)

( expression-list )

new-type-name: (C++ specific)

type-specifiers <new-declarator>

new-declarator: (C++ specific)

ptr-operator <new-declarator>

new-declarator [ <expression> ]

deallocation-expression: (C++ specific)

<::> delete cast-expression

<::> delete [ ] cast-expression

cast-expression:

unary-expression

( type-name )  cast-expression

pm-expression:

cast-expression

pm-expression .* cast-expression (C++ specific)

pm-expression ->* cast-expression (C++ specific)

multiplicative-expression:

pm-expression

multiplicative-expression  *  pm-expression

multiplicative-expression  /  pm-expression

multiplicative-expression  %  pm-expression

additive-expression:

multiplicative-expression

additive-expression  +  multiplicative-expression

additive-expression  -  multiplicative-expression

shift-expression:

additive-expression

shift-expression  <<  additive-expression

shift-expression  >>  additive-expression

relational-expression:

shift-expression

relational-expression  <   shift-expression

relational-expression  >   shift-expression

relational-expression  <=  shift-expression

relational-expression  >=  shift-expression

equality-expression:

relational-expression

equality expression  ==  relational-expression

equality expression  !=  relational-expression

AND-expression:

equality-expression

AND-expression  &  equality-expression

exclusive-OR-expression:

AND-expression

exclusive-OR-expression ^ AND-expression

inclusive-OR-expression:

exclusive-OR-expression

inclusive-OR-expression | exclusive-OR-expression

logical-AND-expression:

inclusive-OR-expression

logical-AND-expression && inclusive-OR-expression

logical-OR-expression:

logical-AND-expression

logical-OR-expression || logical-AND-expression

conditional-expression:

logical-OR-expression

logical-OR-expression ? expression : conditional-expression

assignment-expression:

conditional-expression

unary-expression  assignment-operator  assignment-expression

assignment-operator: one of

=	*=	/=	%=	+=	-=

<<	=>	>=	&=	^=	|=

expression:

assignment-expression

expression , assignment-expression

constant-expression:

conditional-expression


Precedence of operators
Associativity and Precedence of Operators

Operators

There are 16 precedence categories, some of which contain only one operator. Operators in the same category have equal precedence with each other.

Where duplicates of operators appear in the table, the first occurrence is unary, the second binary. Each category has an associativity rule: left to right, or right to left. In the absence of parentheses, these rules resolve the grouping of expressions with operators of equal precedence.

The precedence of each operator in the following table is indicated by its order in the table. The first category (on the first line) has the highest precedence. Operators on the same line have equal precedence.

Operators	Associativity

()	[]	->	::	.							left to right
!	~	+	-	++	--	&	*	sizeof	new	delete	right to left
.*	->*										left to right
*	/	%									left to right
+	-										left to right
<<	>>										left to right
<	<=	>	>=								left to right
==	!=										left to right
&											left to right
^											left to right
|											left to right
&&											left to right
||											right to left
?:											left to right
=	*=	/=	%=	+=	-=	&=	^=	|=	<<=	>>=	right to left
,											left to right


Expressions and C++

See also

C++ allows the overloading of certain standard C operators, as explained in Overloading Operator Functions. An overloaded operator is defined to behave in a special way when applied to expressions of class type. For instance, the equality operator == might be defined in class complex to test the equality of two complex numbers without changing its normal usage with non-class data types.

An overloaded operator is implemented as a function; this function determines the operand type, lvalue, and evaluation order to be applied when the overloaded operator is used. However, overloading cannot change the precedence of an operator. Similarly, C++ allows user-defined conversions between class objects and fundamental types. Keep in mind, then, that some of the C language rules for operators and conversions might not apply to expressions in C++.


Evaluation order

See also

The order in which C++Builder evaluates the operands of an expression is not specified, except where an operator specifically states otherwise. The compiler will try to rearrange the expression in order to improve the quality of the generated code. Care is therefore needed with expressions in which a value is modified more than once. In general, avoid writing expressions that both modify and use the value of the same object. For example, consider the expression

i = v[i++];  // i is undefined

The value of i depends on whether i is incremented before or after the assignment. Similarly,

int total = 0;

sum = (total = 3) + (++total); // sum = 4 or sum = 7 ??

is ambiguous for sum and total. The solution is to revamp the expression, using a temporary variable:

int temp, total = 0;

temp = ++total;

sum = (total = 3) + temp;

Where the syntax does enforce an evaluation sequence, it is safe to have multiple evaluations:

sum = (i = 3, i++, i++); // OK: sum = 4, i = 5

Each subexpression of the comma expression is evaluated from left to right, and the whole expression evaluates to the rightmost value

C++Builder regroups expressions, rearranging associative and commutative operators regardless of parentheses, in order to create an efficiently compiled expression; in no case will the rearrangement affect the value of the expression


Errors and overflows

See also

Associativity and precedence of C++Builder operators. summarizes the precedence and associativity of the operators. During the evaluation of an expression, C++Builder can encounter many problematic situations, such as division by zero or out-of-range floating-point values. Integer overflow is ignored (C uses modulo 2n arithmetic on n-bit registers), but errors detected by math library functions can be handled by standard or user-defined routines.See _matherr and signal.


Operators Summary

See also

Operators are tokens that trigger some computation when applied to variables and other objects in an expression.

Arithmetic

Assignment

Bitwise

C++ specific

Comma

Conditional

Equality

Logical

Postfix Expression Operators

Primary Expression Operators

Preprocessor

Reference/Indirect operators

Relational

sizeof

typeid

All operators can be overloaded except the following:

.	C++ direct component selector

.* 	C++ dereference

::	C++ scope access/resolution

?:	Conditional

Depending on context, the same operator can have more than one meaning. For example, the ampersand (&) can be interpreted as:

a bitwise AND (A & B)

an address operator (&A)

in C++, a reference modifier

Note:	No spaces are allowed in compound operators. Spaces change the meaning of the operator and will generate an error.


Arithmetic Operators

See also	Operators

Syntax

+ cast-expression

- cast-expression

add-expression + multiplicative-expression

add-expression - multiplicative-expression

multiplicative-expr * cast-expr

multiplicative-expr / cast-expr

multiplicative-expr % cast-expr

postfix-expression ++       (postincrement)

++ unary-expression         (preincrement)

postfix-expression --       (postdecrement)

-- unary-expression         (predecrement)

Remarks

Use the arithmetic operators to perform mathematical computations.

The unary expressions of + and - assign a positive or negative value to the cast-expression.

+ (addition), - (subtraction), * (multiplication), and / (division) perform their basic algebraic arithmetic on all data types, integer and floating point.

% (modulus operator) returns the remainder of integer division and cannot be used with floating points.

++ (increment) adds one to the value of the expression. Postincrement adds one to the value of the expression after it evaluates; while preincrement adds one before it evaluates.

-- (decrement) subtracts one from the value of the expression. Postdecrement subtracts one from the value of the expression after it evaluates; while predecrement subtracts one before it evaluates.


Assignment Operators

See also	Operators

Syntax

unary-expr  assignment-op  assignment-expr

Remarks

The assignment operators are:

=    *=     /=     %=    +=    -=

<<=  >>=    &=     ^=    |=

The = operator is the only simple assignment operator, the others are compound assignment operators.

In the expression E1 = E2, E1 must be a modifiable lvalue. The assignment expression itself is not an lvalue.

The expression

E1 op= E2

has the same effect as

E1 = E1 op E2

except the lvalue E1 is evaluated only once. For example, E1 += E2 is the same as E1 = E1 + E2.

The expression's value is E1 after the expression evaluates.

For both simple and compound assignment, the operands E1 and E2 must obey one of the following rules:

1.	E1 is a qualified or unqualified arithmetic type and E2 is an arithmetic type.

2.	E1 has a qualified or unqualified version of a structure or union type compatible with the type of E2.

3.	E1 and E2 are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right.

4.	Either E1 or E2 is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void. The type pointed to by the left has all the qualifiers of the type pointed to by the right.

5.	E1 is a pointer and E2 is a null pointer constant.

Note:	Spaces separating compound operators (+<space>=) will generate errors.


Bitwise operators

See also	Operators

Syntax

AND-expression &  equality-expression

exclusive-OR-expr ^ AND-expression

inclusive-OR-expr exclusive-OR-expression

~cast-expression

shift-expression << additive-expression

shift-expression >> additive-expression

Remarks

Use the bitwise operators to modify the individual bits rather than the number.

Operator	What it does

&	bitwise AND; compares two bits and generates a 1 result if both bits are 1, otherwise it returns 0.

|	bitwise inclusive OR; compares two bits and generates a 1 result if either or both bits are 1, otherwise it returns 0.

^	bitwise exclusive OR; compares two bits and generates a 1 result if the bits are complementary, otherwise it returns 0.

~	bitwise complement; inverts each bit.  ~ is used to create destructors.

>>	bitwise shift right; moves the bits to the right, discards the far right bit and if insigned assignes 0 to the left most bit, otherwise sign extends.

<<	bitwise shift left; moves the bits to the left, it discards the far left bit and assigns 0 to the right most bit.

Both operands in a bitwise expression must be of an integral type.

Bit value	Results of

E1	E2	E1 & E2	E1 ^ E2	E1 | E2

0	0	0	0	0

1	0	0	1	1

0	1	0	1	1

1	1	1	0	1

Note:	&, >>, << are context sensitive. & can also be the pointer reference operator.

>> can also be the input operator in I/O expressions.

<< can also be the output operator in I/O expressions.


C++ Specific Operators

See also	Operators

The operators specific to C++ are:

Operator	Meaning

::	Scope access (or resolution) operator

.*	Dereference pointers to class members

->*	Dereference pointers to pointers to class members

const_cast	adds or removes the const or volatile modifier from a type

delete	dynamically deallocates memory

dynamic_cast	converts a pointer to a desired type

new	dynamically allocates memory

reinterpret_cast	replaces casts for conversions that are unsafe or implementation dependent.

static_cast	converts a pointer to a desired type

typeid	gets run-time identification of types and expressions

Use the scope access (or resolution) operator ::(two semicolons) to access a global (or file duration) name even if it is hidden by a local redeclaration of that name.

Use the .* and ->* operators to dereference pointers to class members and pointers to pointers to class members.


comma operator
Comma Punctuator and Operator

See also	Operators

Syntax

expression , assignment-expression

Remarks

The comma separates elements in a function argument list.

The comma is also used as an operator in comma expressions. Mixing the two uses of comma is legal, but you must use parentheses to distinguish them.

The left operand E1 is evaluated as a void expression, then E2 is evaluated to give the result and type of the comma expression. By recursion, the expression

E1, E2, ..., En

results in the left-to-right evaluation of each Ei, with the value and type of En giving the result of the whole expression.

To avoid ambiguity with the commas in function argument and initializer lists, use parentheses. For example,

func(i, (j = 1, j + 4), k);

calls func with three arguments (i, 5, k), not four.


Conditional operators
Conditional Operator

Operators

Syntax

logical-OR-expr ? expr : conditional-expr

Remarks

The conditional operator ?: is a ternary operator.

In the expression E1 ? E2 : E3, E1 evaluates first. If its value is true, then E2 evaluates and E3 is ignored. If E1 evaluates to false, then E3 evaluates and E2 is ignored.

The result of E1 ? E2 : E3 will be the value of either E2 or E3 depending upon which evaluates.

E1 must be a scalar expression. E2 and E3 must obey one of the following rules:

1.	Both of arithmetic type. E2 and E3 are subject to the usual arithmetic conversions, which determines the resulting type.

2.	Both of compatible struct or union types. The resulting type is the structure or union type of E2 and E3.

3.	Both of void type. The resulting type is void.

4.	Both of type pointer to qualified or unqualified versions of compatible types. The resulting type is a pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.

5.	One operand is a pointer, and the other is a null pointer constant. The resulting type is a pointer to a type qualified with all the type qualifiers of the types pointed to by both operands.

6.	One operand is a pointer to an object or incomplete type, and the other is a pointer to a qualified or unqualified version of void. The resulting type is that of the non-pointer-to-void operand.


Equality operators

See also

There are two equality operators: == and !=. They test for equality and inequality between arithmetic or pointer values, following rules very similar to those for the relational operators.

Note:	Notice that == and != have a lower precedence than the relational operators < and >, <=, and >=. Also, == and != can compare certain pointer types for equality and inequality where the relational operators would not be allowed.

The syntax is

equality-expression:

relational-expression

equality-expression == relational-expression

equality-expression != relational-expression


Logical Operators

Operators

Syntax

logical-AND-expr  && inclusive-OR-expression

logical-OR-expr   || logical-AND-expression

! cast-expression

Remarks

Operands in a logical expression must be of scalar type.

&&	logical AND; returns true only if both expressions evaluate to be nonzero, otherwise returns false. If the first expression evaluates to false, the second expression is not evaluated.

||	logical OR; returns true if either of the expressions evaluate to be nonzero, otherwise returns false. If the first expression evaluates to true, the second expression is not evaluated.

!	logical negation; returns true if the entire expression evaluates to be nonzero, otherwise returns false. The expression !E is equivalent to (0 == E).


Primary Expression Operators

For ANSI C, the primary expressions are literal (also sometimes referred to as constant), identifier, and ( expression ). The C++ language extends this list of primary expressions to include the keyword this, scope resolution operator ::, name, and the class destructor ~ (tilde).

The primary expressions are summarized in the following list.

primary-expression:

literal
this (C++ specific)
:: identifier (C++ specific)
:: operator-function-name (C++ specific)
:: qualified-name (C++ specific)
( expression)
name

literal:

integer-constant
character-constant
floating-constant
string-literal

name:

identifier
perator-function-name (C++ specific)
conversion-function-name (C++ specific)
~ class-name (C++ specific)
qualified-name (C++ specific)

qualified-name: (C++ specific)

qualified-class-name :: name

For a discussion of the primary expression this, see this (keyword). The keyword this cannot be used outside a class member function body.

The scope resolution operator allows reference to a type, object, function, or enumerator even though its identifier is hidden.

The parenthesis surrounding an expression do not change the unadorned expression itself.

The primary expression name is restricted to the category of primary expressions that sometimes appear after the member access operators . (dot) and –> . Therefore, name must be either an lvalue or a function. See also the discussion of member access operators.

An identifier is a primary expression, provided it has been suitably declared. The description and formal definition of identifiers is shown in Lexical Elements: Identifiers.

See the discussion on how to use the destructor operator ~ (tilde).


Postfix expression operators

See also	Operators

Syntax

postfix-expression(<arg-expression-list>)

array declaration [constant-expression]

compound statement { statement list }

postfix-expression . identifier

postfix-expression -> identifier

Remarks

( )	use to group expressions, isolate conditional expressions, indicate function calls and function parameters

{ }	use as the start and end of compound statements

[ ]	use to indicate single and multidimensional array subscripts

.	use to access structure and union members

->	use to access structure and union members

The following postfix expressions let you make safe, explicit typecasts in a C++ program.

const_cast< T > ( expression )

dynamic_cast< T > ( expression )

reinterpret_cast< T > ( expression )

static_cast< T > ( expression )

To obtain runtime type identification (RTTI), use the typeid() operator. The syntax is as follows:

typeid(expression)

typeid(type-name)


Preprocessor Operators

See also	Operators

Remarks

The # (pound sign) is a preprocessor directive when it occurs as the first non-whitespace character on a line.

It signifies a compiler action, not necessarily associated with code generation.

# and ## (double pound signs) also perform operator replacement and merging during the preprocessor scanning phase.


Reference/deference operators
Reference/Dereference Operators

See also	Operators

Syntax

& cast-expression

* cast-expression

Remarks

The & and * operators work together to reference and dereference pointers that are passed to functions.

Referencing operator ( & )

Use the reference operator to pass the address of a pointer to a function outside of main().

The cast-expression operand must be one of the following:

a function designator

an lvalue designating an object that is not a bit field and is not declared with a register storage class specifier

If the operand is of type <type>, the result is of type pointer to <type>.

Some non-lvalue identifiers, such as function names and array names, are automatically converted into “pointer-to-X” types when they appear in certain contexts. The & operator can be used with such objects, but its use is redundant and therefore discouraged.

Consider the following example:

   T t1 = 1, t2 = 2;

   T *ptr = &t1;      // Initialized pointer

   *ptr = t2;           // Same effect as t1 = t2

T *ptr = &t1 is treated as

   T *ptr;

   ptr = &t1;

So it is ptr, or *ptr, that gets assigned. Once ptr has been initialized with the address &t1, it can be safely dereferenced to give the lvalue *ptr.

Indirection operator ( * )

Use the asterisk (*) in a variable expression to create pointers. And use the indirect operator in external functions to get a pointer's value that was passed by reference.

If the operand is of type pointer to function, the result is a function designator.

If the operand is a pointer to an object, the result is an lvalue designating that object.

The result of indirection is undefined if either of the following occur:

1.	The cast-expression is a null pointer.

2.	The cast-expression is the address of an automatic variable and execution of its block has terminated.

Note:	& can also be the bitwise AND operator.

* can also be the multiplication operator.


Relational Operators

See also	Operators

Syntax

relational-expression  <   shift-expression

relational-expression  >   shift-expression

relational-expression  <=  shift-expression

relational-expression  >=  shift-expression

Remarks

Use relational operators to test equality or inequality of expressions. If the statement evaluates to be true it returns a nonzero character; otherwise it returns false (0).

>	greater than

<	less than

>=	greater than or equal

<=	less than or equal

In the expression

E1 <operator> E2

the operands must follow one of these conditions:

1.	Both E1 and E2 are of arithmetic type.

2.	Both E1 and E2 are pointers to qualified or unqualified versions of compatible types.

3.	One of E1 and E2 is a pointer to an object or incomplete type, and the other is a pointer to a qualified or unqualified version of void.

4.	One of E1 or E2 is a pointer and the other is a null pointer constant.


Array subscript operator

See also	Operators

Brackets ([ ]) indicate single and multidimensional array subscripts. The expression

<exp1>[exp2]

is defined as

*((exp1) + (exp2))

where either:

exp1 is a pointer and exp2 is an integer or

exp1 is an integer and exp2 is a pointer


Function call operator

See also	Operators

Syntax

postfix-expression(<arg-expression-list>)

Remarks

Parentheses ()

group expressions

isolate conditional expressions

indicate function calls and function parameters

The value of the function call expression, if it has a value, is determined by the return statement in the function definition.

This is a call to the function given by the postfix expression.

arg-expression-list is a comma-delimited list of expressions of any type representing the actual (or real) function arguments.


. (direct member selector)
Direct member selector

See also	Example	Operators

Syntax

postfix-expression . identifier

postfix-expression must be of type union or structure.

identifier must be the name of a member of that structure or union type.

Remarks

Use the selection operator (.) to access structure and union members.

Suppose that the object s is of struct type S and sptr is a pointer to S. Then, if m is a member identifier of type M declared in S, this expression:

s.m

are of type M, and represent the member object m in s.


Example

struct mystruct {

   int i

   char str[21]

   double d

} s, *sptr=&s

 ...

s.i = 3          // assign to the i member of mystruct s

The expression s.m is an lvalue, provided that s is not an lvalue and m is not an array type.

If structure B contains a field whose type is structure A, the members of A can be accessed by two applications of the member selectors.


-> (indirect, or pointer, member selector)
Indirect member selector

See also	Example	Operators

Syntax

postfix-expression -> identifier

postfix-expression must be of type pointer to structure or pointer to union.

identifier must be the name of a  member of that structure or union type.

The expression designates a member of a structure or union object. The value of the expression is the value of the selected member it will be an lvalue if and only if the postfix expression is an lvalue.

Remarks

You use the selection operator -> to access structure and union members.

Suppose that the object s is of struct type S and sptr is a pointer to S. Then, if m is a member identifier of type M declared in S, this expression:

sptr->m

is of type M, and represents the member object m in s.

The expression

s->sptr

is a convenient synonym for (*sptr).m.


-> Example

struct mystruct {

   int I;

   char str[21];

   double d;

} s, *sptr=&s;

  .

  .

  .

sptr->d = 1.23;   // assign to the d member of mystruct s

The expression sptr->m is an lvalue unless m is an array type.

If structure B contains a field whose type is structure A, the members of A can be accessed by two applications of the member selectors.


Increment/Decrement operators

Operators

Increment operator  ( ++ )

Syntax

postfix-expression ++       (postincrement)

++ unary-expression         (preincrement)

The expression is called the operand it must be of scalar type (arithmetic or pointer types) and must be a modifiable lvalue..

Postincrement operator

The value of the whole expression is the value of the postfix expression before the increment is applied.

After the postfix expression is evaluated,the operand is incremented by 1.

Preincrement operator

The operand is incremented by 1 before the expression is evaluated the value of the whole expression is the incremented value of the operand.

The increment value is appropriate to the type of the operand.

Pointer types follow the rules for pointer arithmetic.

Decrement operator  ( -- )

Syntax

postfix-expression --       (postdecrement)

-- unary-expression         (predecrement)

The decrement operator follows the same rules as the increment operator, except that the operand is decremented by 1 after or before the whole expression is evaluated.


Unary operators

See also	Operators

Syntax

<unary-operator> <unary expression>

OR

<unary-operator> <type><unary expression>

Remarks

Unary operators group right-to-left.

C++Builder provides the following unary operators:

!   Logical negation

*   Indirection

++  Increment

~   Bitwise complement

--  Decrement

-   Unary minus

+   Unary plus


Plus and Minus Operators

See also	Operators

Unary

In these unary + - expressions

+ cast-expression

- cast-expression

the cast-expression operand must be of arithmetic type.

Results

+ cast-expression	Value of the operand after any required integral promotions.

- cast-expression	Negative of the value of the operand after any required integral promotions.

Binary

Syntax

add-expression + multiplicative-expression

add-expression - multiplicative-expression

Legal operand types for op1 + op2:

1.	Both op1 and op2 are of arithmetic type.

2.	op1 is of integral type, and op2 is of pointer to object type.

3.	op2 is of integral type, and op1 is of pointer to object type.

In case 1, the operands are subjected to the standard arithmetical conversions, and the result is the arithmetical sum of the operands.

In cases 2 and 3, the rules of pointer arithmetic apply.

Legal operand types for op1 - op2:

1.	Both op1 and op2 are of arithmetic type.

2.	Both op1 and op2 are pointers to compatible object types.

3.	op1 is of pointer to object type, and op2 is integral type.

In case 1, the operands are subjected to the standard arithmetic conversions, and the result is the arithmetic difference of the operands.

In cases 2 and 3, the rules of pointer arithmetic apply.

Note:	The unqualified type <type> is considered to be compatible with the qualified types const type, volatile type,and const volatile type.


Binary operators

See also	Operators

These are the binary operators in Borland C++:

Arithmetic	+ 	Binary plus (add)

- 	Binary minus (subtract)

*	Multiply

/	Divide

% 	Remainder (modulus)

Bitwise	<<	Shift left

>>	Shift right

&	Bitwise AND

^   	Bitwise XOR (exclusive OR)

|   	Bitwise inclusive OR

Logical	&&  	Logical AND

||  	Logical OR

Assignment	=   	Assignment

*= 	Assign product

/=  	Assign quotient

%=  	Assign remainder (modulus)

+=  	Assign sum

-=  	Assign difference

<<= 	Assign left shift

 >>= 	Assign right shift

&=  	Assign bitwise AND

 ^=  	Assign bitwise XOR

|=  	Assign bitwise OR

Relational	<   	Less than

>   	Greater than

<=  	Less than or equal to

>=  	Greater than or equal to

==  	Equal to

!=  	Not equal to

Component selection	. 	Direct component selector

->  	Indirect component selector

Class-member	:: 	Scope access/resolution

.*  	Dereference pointer to class member

->* 	Dereference pointer to class member

Conditional	? : 	Actually a ternary operator for example,

a ? x : y 	"if a then x else y"

Comma	,	Evaluate


Multiplicative Operators

Operators

Syntax

multiplicative-expr * cast-expr

multiplicative-expr / cast-expr

multiplicative-expr % cast-expr

Remarks

There are three multiplicative operators:

*	(multiplication)

/	(division)

%	(modulus or remainder)

The usual arithmetic conversions are made on the operands.

(op1 * op2)  Product of the two operands

(op1 / op2)  Quotient of (op1 divided by op2)

(op1 % op2)  Remainder of (op1 divided by op2)

For / and %, op2 must be nonzero op2 = 0 results in an error. (You can't divide by zero.)

When op1 and op2 are integers and the quotient is not an integer:

1.	If op1 and op2 have the same sign, op1 / op2 is the largest integer less than the true quotient, and op1 % op2 has the sign of op1.

2.	If op1 and op2 have opposite signs, op1 / op2 is the smallest integer greater than the true quotient, and op1 % op2 has the sign of op1.

Note:	Rounding is always toward zero.

* is context sensitive and can be used as the pointer reference operator.


Statements

See also

Statements specify the flow of control as a program executes. In the absence of specific jump and selection statements, statements are executed sequentially in the order of appearance in the source code. C++Builder statements shows the syntax for statements.

C++Builder statements

statement:

labeled-statement

compound-statement

expression-statement

selection-statement

iteration-statement

jump-statement

asm-statement

declaration (C++ specific)

labeled-statement:

identifier  :  statement

case  constant-expression  :  statement

default  :  statement

compound-statement:

{  <declaration-list>  <statement-list>  }

declaration-list:

declaration

declaration-list  declaration

statement-list:

statement

statement-list  statement

expression-statement:

<expression> ;

asm-statement:

asm  tokens  newline

asm  tokens;

asm  { tokens; <tokens;>= <tokens;>}

selection-statement:

if  ( expression )  statement

if  ( expression )  statement else  statement

switch  ( expression )  statement

iteration-statement:

while  (  expression )  statement

do  statement  while  ( expression ) ;

for  (for-init-statement <expression>  ;  <expression>) statement

for-init-statement:

expression-statement

declaration (C++ specific)

jump-statement:

goto  identifier ;

continue  ;

break  ;

return  <expression> ;


Blocks

See also

A compound statement, or block, is a list (possibly empty) of statements enclosed in matching braces ({ }). Syntactically, a block can be considered to be a single statement, but it also plays a role in the scoping of identifiers. An identifier declared within a block has a scope starting at the point of declaration and ending at the closing brace. Blocks can be nested to any depth up to the limits of memory.


Labeled statements

See also

A statement can be labeled in two ways:

 	label-identifier : statement

The label identifier serves as a target for the unconditional goto statement. Label identifiers have their own name space and have function scope. In C++ you can label both declaration and non-declaration statements.

 	case constant-expression : statement

default : statement

Case and default labeled statements are used only in conjunction with switch statements.


Expression statements

See also

Any expression followed by a semicolon forms an expression statement:

<expression>;

C++Builder executes an expression statement by evaluating the expression. All side effects from this evaluation are completed before the next statement is executed. Most expression statements are assignment statements or function calls

The null statement is a special case, consisting of a single semicolon (;). The null statement does nothing, and is therefore useful in situations where the C++Builder syntax expects a statement but your program does not need one.


Selection statements

See also

Selection or flow-control statements select from alternative courses of action by testing certain values. There are two types of selection statements: the if...else and the switch.


Iteration statements

See also

Iteration statements let you loop a set of statements. There are three forms of iteration in C++Builder: while, do while, and for loops.


Jump statements

See also

A jump statement, when executed, transfers control unconditionally. There are four such statements: break, continue, goto, and return


C++ specifics

See also

C++ is an object-oriented programming language based on C. Generally speaking, you can compile C programs under C++, but you can’t compile a C++ program under C if the program uses any constructs specific to C++. Some situations require special care. For example, the same function func declared twice in C with different argument types invokes a duplicated name error. Under C++, however, func will be interpreted as an overloaded function; whether or not this is legal depends on other circumstances.

Although C++ introduces new keywords and operators to handle classes, some of the capabilities of C++ have applications outside of any class context. This topic discusses the aspects of C++ that can be used independently of classes, then describes the specifics of classes and class mechanisms.

See C++ Exception Handling and C-Based Structured Exceptions for details on compiling C and C++ programs with exception handling.


namespace

See Also

Category

C++-Specific Keywords

Description

Most nontrivial applications consist of more than one source file. The files can be authored and maintained by more than one developer. Eventually, the separate files are organized and linked to produce the final application. Traditionally, the file organization requires that all names that aren't encapsulated within a defined namespace (such as function or class body, or translation unit) must share the same global namespace. Therefore, multiple definitions of names discovered while linking separate modules require some way to distinguish each name. The solution to the problem of name clashes in the global scope is provided by the C++ namespace mechanism.

The namespace mechanism allows an application to be partitioned into a number of subsystems. Each subsystem can define and operate within its own scope. Each developer is free to introduce whatever identifiers are convenient within a subsystem without worrying about whether such identifiers are being used by someone else. The subsystem scope is known throughout the application by a unique identifier.

It only takes two steps to use C++ namespaces. The first is to uniquely identify a namespace with the keyword namespace. The second is to access the elements of an identified namespace by applying the using keyword.


Defining a namespace

SeeAlso

The grammar for defining a namespace is

   original-namespace-name:

      identifier

   namespace-definition:

      original-namespace-definition

      extension-namespace-definition

      unnamed-namespace-definition

Grammatically, there are three ways to define a namespace with the namespace keyword:

   original-namespace-definition:

         namespace identifier { namespace-body }

   extension-namespace-definition:

         namespace original-namespace-name { namespace-body }

   unnamed-namespace-definition:

         namespace { namespace-body }

The body is an optional sequence of declarations. The grammar is

   namespace-body:

      declaration-seq opt


Example
Example for extending namespaces

// An example for extending namespaces

#include <iostream.h>

   struct S { };

   class C  { };

   namespace ALPHA {  // ALPHA is an original identifier.

      void g(struct S) {

         cout << "Processing a structure argument" << endl;

         }

      }

   using ALPHA::g;  // using-declaration

   /*** After the using-declaration above, subsequent attempts

        to overload the g() function are ignored. ***/

   namespace ALPHA { // Extending the ALPHA namespace

      void g( C& ) { // Overloaded version of function

         cout << "Processing a class argument." << endl;

         }

      }

   int main() {

      S mystruct;

      C myclass;

      g(mystruct);

      // The following function call fails at compile-time

      // because there is no overloaded version for this case.

 //      g(myclass);

      return 0;

   }

Output:

Processing a structure argument


Declaring a namespace

SeeAlso

An original namespace declaration should use an identifier that has not been previously used as a global identifier.

    namespace ALPHA {  /* ALPHA is the identifier of this namespace. */

      /* your program declarations */

      long double LD;

      float f(float y) { return y; }

      }

A namespace identifier must be known in all translation units where you intend to access it's elements.


Namespace alias

You can use an alternate name to refer to a namespace identifier. An alias is useful when you need to refer to a long, unwieldy namespace identifier.

  namespace BORLAND_INTERNATIONAL {

     /* namespace-body */

     namespace NESTED_BORLAND_INTERNATIONAL {

        /* namespace-body */

        }

     }

  // Alias namespace

  namespace BI = BORLAND_INTERNATIONAL;

  // Use access qualifier to alias a nested namespace

  namespace NBI = BORLAND_INTERNATIONAL::NESTED_BORLAND_INTERNATIONAL;


Extending a namespace

Example

Namespaces are discontinuous and open for additional development. If you redeclare a namespace, the effect is that you extend the original namespace by adding new declarations. Any extensions that are made to a namespace after a using-declaration, will not be known at the point at which the using-declaration occurs. Therefore, all overloaded versions of some function should be included in the namespace before you declare the function to be in use.


Anonymous namespaces

Example

The C++ grammar allows you to define anonymous namespaces. To do this,you use the keyword namespace with no identifier before the enclosing brace.

namespace {          // Anonymous namespace

   // Declarations

   }

All anonymous, unnamed namespaces in global scope (that is, unnamed namespaces that are not nested) of the same translation unit share the same namespace. This way you can make static declarations without using the static keyword.

Each identifier that is enclosed within an unnamed namespace is unique within the translation unit in which the unnamed namespace is defined.


Example

In file ANON1.CPP

#include <iostream.h>

extern void func(void);

namespace {          // Anonymous

   float pi = 3.14;  // Unique identifier known only in this file

   }

void main() {

   float pi = 0.1;

   cout << "pi = " << pi << endl;

   func();

   }

In file ANON2.CPP

#include <iostream.h>

namespace {             // Anonymous namespace

   float pi = 10.0001;  // Unique identifier known only in this file

   void func(void) {

       cout << "First func() called; pi = " << pi;

       }

   }

   void func(void) {

       cout << "Second func() called; pi = " << pi;

       }

Program output:

pi = 0.1

func() called; pi = 10.0001


Accessing elements of a namespace

See also

There are three ways to access the elements of a namespace: by explicit access qualification, the using-declaration, or the using-directive. Remember that no matter which namespace you add to your local scope, identifiers in global scope (global scope is just another namespace) are still accessible by using the scope resolution operator ::.

Explicit access qualification

Using directive

Using declaration

Accessing namespaces in classes

Example

You cannot use a using directive inside a class. However, the using declarative is allowed and can be quite useful.


Example

// An example for accessing a namespace within a class.

// This allows us to overload a function which is a base class member.

#include <iostream.h>

   class A {

   public:

      void func(char ch) { cout << "char = " << ch << endl; }

   };

   class B : public A {

   public:

//      using namespace A;   // ERROR. The using directive isn’t allowed

      void func(char *str) { cout << "string = " << str << endl; }

      // The using declarative

      using A::func;        // Overload B::func()

   };

   int main() {

      B b;

      b.func('c');  // Calls A::func()

      b.func("c");  // Calls B::func()

      return 0;

   }


Using directive

See also	Example

If you want to use several (or all of) the members of a namespace, C++ provides an easy way to get access to the complete namespace. The using-directive specifies that all identifiers in a namespace are in scope at the point that the using-directive statement is made. The grammar for the using-directive is as follows.

   using-directive:

      using namespace  :: opt nested-name-specifier opt namespace-name;

The using-directive is transitive. That means that when you apply the using directive to a namespace that contains using directives within itself, you get access to those namespaces as well. For example, if you apply the using directive in your program, you also get namespaces A, ONE, and TWO.

   namespace A {

      using namespace ONE;  // This has been defined previously

      using namespace TWO;  // This also has been defined previously

      }

The using-directive does not add any identifiers to your local scope. Therefore, an identifier defined in more than one namespace won't be a problem until you actually attempt to use it. Local scope declarations take precedence by hiding all other similar declarations.


Example

// AN EXAMPLE OF THE using DIRECTIVE

#include <iostream.h>

   namespace F {

      float x = 9;

      }

   namespace G {

      using namespace F;

      float y = 2.0;

         namespace INNER_G {

            float z = 10.01;

            }

      }

   int main() {

      using namespace G;  // THIS DIRECTIVE GIVES YOU EVERYTHING DECLARED IN "G"

      using namespace G::INNER_G;  // THIS DIRECTIVE GIVES YOU ONLY "INNER_G"

      float x = 19.1;     // LOCAL DECLARATION TAKES PRECEDENCE

      cout << "x = " << x << endl;

      cout << "y = " << y << endl;

      cout << "z = " << z << endl;

      return 0;

      }

Output:

   x = 19.1

   y = 2

   z = 10.01


using (declaration)

See also	Example

Category

C++-Specific Keywords

Description

You can access namespace members individually with the using-declaration syntax. When you make a using declaration, you add the declared identifier to the local namespace. The grammar is

   using-declaration:

          using :: unqualified-identifier;


Example

// An example of the using declaration.

// The function g() is defined in two different namespaces.

#include <iostream.h>

namespace ALPHA {  /* ALPHA is the name of this namespace. */

   float f(float y) { return y; }

   void g() { cout << "ALPHA version" << endl; }

   }

namespace BETA {  /* BETA is the name of this namespace. */

      void g() { cout << "BETA version" << endl; }

         }

void main(void) {

// The using declaration identifies the desired version of g().

         using ALPHA::f;  // Qualified declaration

         using BETA::g;   // Qualified declaration

         float x = 0;

         // Access qualifiers are no longer needed.

         x = f(2.1);

         g();

         }


Explicit access qualification

You can explicitly qualify each member of a namespace. To do so, you use the namespace identifier together with the :: scope resolution operator followed by the member name. For example, to access a specific member of namespace ALPHA, you write:

      ALPHA::LD;  // Access a variable

      ALPHA::f;   // Access a function

Explicit access qualification can always be used to resolve ambiguity. No matter which namespace (except anonymous namespace) is being used in your subsystem, you can apply the scope resolution operator :: to access identifiers in any namespace (including a namespace already being used in the local scope) or the global namespace. Therefore, any identifier in the application can be accessed with sufficient qualification.

New-stye typecasting

This section presents a discussion of alternate methods for making a typecast. The methods presented here augment the earlier cast expressions (which are still available) in the C language.

Types cannot be defined in a cast.


New-style typecasting

See also

This section presents a discussion of alternate methods for making a typecast. The methods presented here augment the earlier cast expressions (which are still available) in the C language.

Types cannot be defined in a cast.


const_cast (typecast operator)
const_cast

See also

Category

C++-Specific Keywords

Syntax

const_cast< T > (arg)

Description

Use the const_cast operator to add or remove the const or volatile modifier from a type.

In the statement, const_cast< T > (arg), T and arg must be of the same type except for const and volatile modifiers. The cast is resolved at compile time. The result is of type T. Any number of const or volatile modifiers can be added or removed with a single const_cast expression.

A pointer to const can be converted to a pointer to non-const that is in all other respects an identical type. If successful, the resulting pointer refers to the original object.

A const object or a reference to const cast results in a non-const object or reference that is otherwise an identical type.

The const_cast operator performs similar typecasts on the volatile modifier. A pointer to volatile object can be cast to a pointer to non-volatile object without otherwise changing the type of the object. The result is a pointer to the original object. A volatile-type object or a reference to volatile-type can be converted into an identical non-volatile type.


dynamic_cast (typecast operator)
dynamic_cast

See also	Example

Category

C++-Specific Keywords

Description

In the expression, dynamic_cast< T > (ptr), T must be a pointer or a reference to a defined class type or void*. The argument ptr must be an expression that resolves to a pointer or reference.

If T is void* then ptr must also be a pointer. In this case, the resulting pointer can access any element of the class that is the most derived element in the hierarchy. Such a class cannot be a base for any other class.

Conversions from a derived class to a base class, or from one derived class to another, are as follows: if T is a pointer and ptr is a pointer to a non-base class that is an element of a class hierarchy, the result is a pointer to the unique subclass. References are treated similarly. If T is a reference and ptr is a reference to a non-base class, the result is a reference to the unique subclass.

A conversion from a base class to a derived class can be performed only if the base is a polymorphic type.

The conversion to a base class is resolved at compile time. A conversion from a base class to a derived class, or a conversion across a hierarchy is resolved at runtime.

If successful, dynamic_cast< T > (ptr) converts ptr to the desired type. If a pointer cast fails, the returned pointer is valued 0. If a cast to a reference type fails, the Bad_cast exception is thrown.

Note:	Runtime type identification (RTTI) is required for dynamic_cast.


// dynamic_cast Example

// HOW TO MAKE DYNAMIC CASTS

// This program must be compiled with the -RT (Generate RTTI) option.

#include <iostream.h>

#include <typeinfo.h>

class Base1

{

   // In order for the RTTI mechanism to function correctly,

   // a base class must be polymorphic.

   virtual void f(void) { /* A virtual function makes the class polymorphic */ }

};

class Base2 { };

class Derived : public Base1, public Base2 { };

int main(void) {

   try {

      Derived d, *pd;

      Base1 *b1 = &d;

      // Perform a downcast from a Base1 to a Derived.

      if ((pd = dynamic_cast<Derived *>(b1)) != 0) {

           cout << "The resulting pointer is of type "

                << typeid(pd).name() << endl;

         }

      else throw Bad_cast();

      // Attempt cast across the hierarchy.  That is, cast from

      // the first base to the most derived class and then back

      // to another accessible base.

      Base2 *b2;

      if ((b2 = dynamic_cast<Base2 *>(b1)) != 0) {

          cout << "The resulting pointer is of type "

               << typeid(b2).name() << endl;

         }

      else throw Bad_cast();

      }

   catch (Bad_cast) {

      cout << "dynamic_cast failed" << endl;

      return 1;

      }

   catch (...) {

      cout << "Exception handling error." << endl;

      return 1;

      }

   return 0;

}


reinterpret_cast (typecast operator)
reinterpret_cast

See also	Example

Category

C++-Specific Keywords

Syntax

reinterpret_cast< T > (arg)

Description

In the statement, reinterpret_cast< T > (arg), T must be a pointer, reference, arithmetic type, pointer to function, or pointer to member.

A pointer can be explicitly converted to an integral type.

An integral arg can be converted to a pointer. Converting a pointer to an integral type and back to the same pointer type results in the original value.

A yet undefined class can be used in a pointer or reference conversion.

A pointer to a function can be explicitly converted to a pointer to an object type provided the object pointer type has enough bits to hold the function pointer. A pointer to an object type can be explicitly converted to a pointer to a function only if the function pointer type is large enough to hold the object pointer.


// reinterpret_cast Example

// Use reinterpret_cast<Type>(expr) to replace (Type)expr casts

// for conversions that are unsafe or implementation dependent.

void func(void *v) {

        // Cast from pointer type to integral type.

        int i = reinterpret_cast<int>(v);

  .

  .

  .

}

void main() {

   // Cast from an integral type to pointer type.

   func(reinterpret_cast<void *>(5));

   // Cast from a pointer to function of one type to

   // pointer to function of another type.

   typedef void (* PFV)();

   PFV pfunc = reinterpret_cast<PFV>(func);

   pfunc();

   }


static_cast (typecast operator)
static_cast

See also

Category

C++-Specific Keywords

Syntax

static_cast< T > (arg)

Description

In the statement, static_cast< T > (arg), T must be a pointer, reference, arithmetic type, or enum type. The arg-type must match the T-type. Both T and arg must be fully known at compile time.

If a complete type can be converted to another type by some conversion method already provided by the language, then making such a conversion by using static_cast achieves exactly the same thing.

Integral types can be converted to enum types. A request to convert arg to a value that is not an element of enum is undefined.

The null pointer is converted to itself.

A pointer to one object type can be converted to a pointer to another object type. Note that merely pointing to similar types can cause access problems if the similar types are not similarly aligned.

You can explicitly convert a pointer to a class X to a pointer to some class Y if X is a base class for Y. A static conversion can be made only under the following conditions:

if an unambiguous conversion exists from Y to X

if X is not a virtual base class

An object can be explicitly converted to a reference type X& if a pointer to that object can be explicitly converted to an X*. The result of the conversion is an lvalue. No constructors or conversion functions are called as the result of a cast to a reference.

An object or a value can be converted to a class object only if an appropriate constructor or conversion operator has been declared.

A pointer to a member can be explicitly converted into a different pointer-to-member type only if both types are pointers to members of the same class or pointers to members of two classes, one of which is unambiguously derived from the other.

When T is a reference the result of static_cast< T > (arg) is an lvalue. The result of a pointer or reference cast refers to the original expression.


Run-time type identification (RTTI) overview

See also

Run-time type identification (RTTI) lets you write portable code that can determine the actual type of a data object at run time even when the code has access only to a pointer or reference to that object. This makes it possible, for example, to convert a pointer to a virtual base class into a pointer to the derived type of the actual object. Use the dynamic_cast operator to make run-time casts.

The RTTI mechanism also lets you check whether an object is of some particular type and whether two objects are of the same type. You can do this with typeid operator, which determines the actual type of its argument and returns a reference to an object of type const type_info, which describes that type.

You can also use a type name as the argument to typeid, and typeid will return a reference to a const type_info object for that type. The class type_info provides an operator== and an operator!= that you can use to determine whether two objects are of the same type. Class type_info also provides a member function name that returns a pointer to a character string that holds the name of the type.


__rtti Example

/* HOW TO GET RUN-TIME TYPE INFORMATION FOR POLYMORPHIC CLASSES.*/

#include <iostream.h>

#include <typeinfo.h>

class __rtti Alpha {        /* Provide RTTI for this class and */

                             /* all classes derived from it */

    virtual void func() {};  /* A virtual function makes */

                             /* Alpha a polymorphic class. */

};

class B : public Alpha {};

int main(void) {

   B Binst;           // Instantiate class B

   B *Bptr;           // Declare a B-type pointer

   Bptr = &Binst;     // Initialize the pointer

   // THESE TESTS ARE DONE AT RUN TIME

   try {

      if (typeid( *Bptr ) == typeid( B ) )

          // Ask "WHAT IS THE TYPE FOR *Bptr?"

          cout << "Name is " << typeid( *Bptr).name();

      if (typeid( *Bptr ) != typeid( Alpha ) )

          cout << "\nPointer is not an Alpha-type.";

      return 0;

      }

   catch (Bad_typeid) {

      cout << "typeid() has failed.";

      return 1;

      }

   }

Program Output

Name is B

Pointer is not an Alpha-type.


The typeid operator

See also	Example	Keywords

Syntax

typeid( expression )

typeid( type-name )

Description

You can use typeid to get run-time identification of types and expressions. A call to typeid returns a reference to an object of type const type_info. The returned object represents the type of the typeid operand.

If the typeid operand is a dereferenced pointer or a reference to a polymorphic type, typeid returns the dynamic type of the actual object pointed or referred to. If the operand is non-polymorphic, typeid returns an object that represents the static type.

You can use the typeid operator with fundamental data types as well as user-defined types.

If the typeid operand is a dereferenced NULL pointer, the Bad_typeid exception is thrown.


__rtti, -RT option

See also	Example	Keywords

Category (__rtti keyword)

Modifiers, C++Builder Keyword Extensions, C++-Specific Keywords

Description

RTTI is enabled by default in C++Builder. You can use the  -RT- command-line option to disable it or -RT to enable it. If RTTI is disabled, or if the argument to typeid is a pointer or a reference to a non-polymorphic class, typeid returns a reference to a const type_info object that describes the declared type of the pointer or reference, and not the actual object that the pointer or reference is bound to.

In addition, even when RTTI is disabled, you can force all instances of a particular class and all classes derived from that class to provide polymorphic run-time type identification (where appropriate) by using the C++Builder keyword __rtti in the class definition.

When you use the -RT- compiler option, if any base class is declared __rtti, then all polymorphic base classes must also be declared __rtti.

struct __rtti S1 { virtual s1func(); };  /* Polymorphic */

struct __rtti S2 { virtual s2func(); };  /* Polymorphic */

struct X : S1, S2 { };

If you turn off the RTTI mechanism (by using the -RT- compiler option), RTTI might not be available for derived classes. When a class is derived from multiple classes, the order and type of base classes determines whether or not the class inherits the RTTI capability.

When you have polymorphic and non-polymorphic classes, the order of inheritance is important. If you compile the following declarations with -RT-, you should declare X with the __rtti modifier. Otherwise, switching the order of the base classes for the class X results in the compile-time error Can't inherit non-RTTI class from RTTI base 'S1'.

struct __rtti S1 { virtual func(); };   /* Polymorphic class */

struct S2 { };                           /*  Non-polymorphic class */

struct __rtti X : S1, S2 { };

Note:	The class X is explicitly declared with __rtti. This makes it safe to mix the order and type of classes.

In the following example, class X inherits only non-polymorphic classes. Class X does not need to be declared __rtti.

struct __rtti S1 {  };   // Non-polymorphic class

struct S2 { };

struct X : S2, S1 { };   // The order is not essential

Applying either __rtti or using the -RT compiler option will not make a static class into a polymorphic class.


-RT option and destructors

When -xd is enabled, a pointer to a class with a virtual destructor can't be deleted if that class is not compiled with -RT. The -RT and -xd options are on by default.

Example

class Alpha {

public:

   virtual ~Alpha( ) { }

};

void func( Alpha *Aptr ) {

   delete Aptr;         // Error.  Alpha is not a polymorphic class type

   }


Referencing

See also

While in C, you pass arguments only by value; in C++, you can pass arguments by value or by reference. C++ reference types, closely related to pointer types, create aliases for objects and let you pass arguments to functions by reference. See the following topics for a discussion of referencing.

Simple references

Reference arguments

Reference/Indirect operators

Note:	C++ specific pointer referencing and dereferencing is discussed in C++ specific operators.


Simple references

See also

The reference declarator can be used to declare references outside functions:

int  i  = 0;

int &ir = i;   // ir is an alias for i

ir = 2;        // same effect as i = 2

Note that type& var, type &var, and type & var are all equivalent.

This creates the lvalue ir as an alias for i, provided the initializer is the same type as the reference. Any operations on ir have precisely the same effect as operations on i. For example, ir = 2 assigns 2 to i, and &ir returns the address of i.


Reference arguments

See also

The reference declarator can also be used to declare reference type parameters within a function:

void func1 (int i);

void func2 (int &ir);    // ir is type "reference to int"

    .

    .

    .

int sum=3;

func1(sum);              // sum passed by value

func2(sum);             // sum passed by reference

The sum argument passed by reference can be changed directly by func2. On the other hand, func1 gets a copy of the sum argument (passed by value), so sum itself cannot be altered by func1.

When an actual argument x is passed by value, the matching formal argument in the function receives a copy of x. Any changes to this copy within the function body are not reflected in the value of x itself. Of course, the function can return a value that could be used later to change x, but the function cannot directly alter a parameter passed by value.

The C method for changing x uses the actual argument &x, the address of x, rather than x itself. Although &x is passed by value, the function can access x through the copy of &x it receives. Even if the function does not need to change x, it is still useful (though subject to potentially dangerous side effects) to pass &x, especially if x is a large data structure. Passing x directly by value involves wasteful copying of the data structure.

Compare the three implementations of the function treble:

Implementation 1

int treble_1(int n)

{

   return 3 * n;

}

  .

  .

  .

int x, i = 4;

x = treble_1(i);         // x now = 12, i = 4

  .

  .

  .

Implementation 2

void treble_2(int* np)

{

   *np = (*np) * 3;

}

  .

  .

  .

treble_2(int& i);        // i now = 12

Implementation 3

void treble_3(int& n)    // n is a reference type

{

   n = 3 * n;

}

  .

  .

  .

treble_3(i);             // i now = 36

The formal argument declaration type& t (or equivalently, type& t) establishes t as type “reference to type.” So, when treble_3 is called with the real argument i, i is used to initialize the formal reference argument n. n therefore acts as an alias for i, so n = 3*n also assigns 3 * i to i.

If the initializer is a constant or an object of a different type than the reference type, creates a temporary object for which the reference acts as an alias:

int& ir = 6;   /* temporary int object created, aliased by ir, gets value 6 */

float f;

int& ir2 = f;  /* creates temporary int object aliased by ir2; f converted

                  before assignment */

ir2 = 2.0      // ir2 now = 2, but f is unchanged

The automatic creation of temporary objects permits the conversion of reference types when formal and actual arguments have different (but assignment-compatible) types. When passing by value, of course, there are fewer conversion problems, since the copy of the actual argument can be physically changed before assignment to the formal argument.


Scope resolution operator ::

The scope access (or resolution) operator :: (two colons) lets you access a global (or file duration) member name even if it is hidden by a local redeclaration of that name. You can use a global identifiers by prefixing it with the resolution operator. To access a nested member name by specifying the class name and using the resolution operator. Therefore, Alpha::func( ) and Beta::func( ) are two different functions.


new

See also	Example	Operators

Category

Operators, C++-Specific Keywords

Syntax

<::> new <placement> type-name <(initializer)>

<::> new <placement> (type-name) <(initializer)>

Description

The new operator offers dynamic storage allocation, similar but superior to the standard library function malloc. The new operator must always be supplied with a data type in place of type-name. Items surrounded by angle brackets are optional. The optional arguments can be as follows:

:: operator, invokes the global version of new.

placement can be used to supply additional arguments to new. You can use this syntax only if you have have an overloaded version of new that matches the optional arguments. See the discussion of the placement syntax.

initializer, if present is used to initialize the allocation. Arrays cannot be initialized by the allocation operator.

A request for non-array allocation uses the appropriate operator new() function. Any request for array allocation will call the appropriate operator new[]() function. The selection of the allocation operator is done as follows:

Allocation of arrays of Type:

1.	Attempts to use a class-specific array allocator:

Type::operator new[]()

2.	If the class-specific array allocator is not defined, the global version is used:

::operator new[]()

Allocation of non-arrays of Type:

1.	Attempts to used the class-specific allocator:

Type::operator new()

2.	If the class-specific array allocator is not defined, the global version is used:

::operator new()

Allocation of single objects (that are not class-type) which are not held in arrays:

1.	Memory allocation for a non-array object is by using the ::operator new(). Note that this allocation function is always used for the predefined types. It is possible to overload this global operator function. However, this is generally not advised.

Allocation of arrays:

1.	Use the global allocation operator:

::operator new[] ()

Note:	Arrays of classes require the default constructor.

new tries to create an object of type Type by allocating (if possible) sizeof(Type) bytes in free store (also called the heap). new calculates the size of Type without the need for an explicit sizeof operator. Further, the pointer returned is of the correct type, "pointer to Type," without the need for explicit casting. The storage duration of the new object is from the point of creation until the operator delete destroys it by deallocating its memory, or until the end of the program.

If successful, new returns a pointer to the allocated memory. By default, an allocation failure (such as insufficient or fragmented heap memory) results in the predefined exception bad_alloc being thrown. Your program should always be prepared to catch the bad_alloc exception before trying to access the new object (unless you use a new-handler).

A request for allocation of 0 bytes returns a non-null pointer. Repeated requests for zero-size allocations return distinct, non-null pointers.


delete

See also	Example	Operators

Category

Operators, C++-Specific Keywords

Syntax

<::> delete <cast-expression>

<::> delete [ ] <cast-expression>

delete <array-name> [ ];

Description

The delete operator offers dynamic storage deallocation, deallocating a memory block allocated by a previous call to new. It is similar but superior to the standard library function free.

You should use the delete operator to remove all memory which has been allocated by the new operator. Failure to free memory can result in memory leaks.


Operator new placement syntax

Example

The placement syntax for operator new( ) can be used only if you have overloaded the allocation operator with the appropriate arguments. You can use the placement syntax when you want to use and reuse a memory space which you set up once at the beginning of your program.

When you use the overloaded operator new( ) to specify where you want an allocation to be placed, you are responsible for deleting the allocation. Because you call your version of the allocation operator, you cannot depend on the global ::operator delete( ) to do the cleanup.

To release memory, you make an explicit call on the destructor. This method for cleaning up memory should be used only in special situations and with great care. If you make an explicit call of a destructor before an object that has been constructed on the stack goes out of scope, the destructor will be called again when the stackframe is cleaned up.


Handling Errors for the new Operator

See also

By default, new throws the bad_alloc exception when a request for memory allocation cannot be satisfied.

You can define a function to be called if the new operator fails. To tell the new operator about the new-handler function, use set_new_handler and supply a pointer to the new-handler. If you want new to return null on failure, you must use set_new_handler(0) .


The Operator new With Arrays

Example

If Type is an array, the pointer returned by operator new[]() points to the first element of the array. When creating multidimensional arrays with new, all array sizes must be supplied (although the leftmost dimension doesn't have to be a compile-time constant):

mat_ptr = new int[3][10][12];    // OK

mat_ptr = new int[n][10][12];    // OK

mat_ptr = new int[3][][12];      // illegal

mat_ptr = new int[][10][12];     // illegal

Although the first array dimension can be a variable, all following dimensions must be constants.


The delete Operator with Arrays

Arrays are deleted by operator delete[](). You must use the syntax delete [] expr when deleting an array.

char * p;

void func()

{

   p = new char[10];    //  allocate 10 chars

   delete[] p;          // delete 10 chars

}

C++ 2.0 code required the array size to be named in the delete expression. In order to allow 2.0 code to compile, C++Builder issues a warning and simply ignores any size that is specified. For example, if the preceding example reads delete[10] p and is compiled, the warning is as follows:

Warning: Array size for 'delete' ignored in function func()


operator new

See also

By default, if there is no overloaded version of new, a request for dynamic memory allocation always uses the global version of new, ::operator new(). A request for array allocation calls ::operator new[](). With class objects of type name, a specific operator called name::operator new() or name::operator new[]() can be defined. When new is applied to class name objects it invokes the appropriate name::operator new if it is present; otherwise, the global ::operator new is used.

Only the operator new() function will accept an optional initializer. The array allocator version, operator new[](), will not accept initializers. In the absence of explicit initializers, the object created by new contains unpredictable data (garbage). The objects allocated by new, other than arrays, can be initialized with a suitable expression between parentheses:

   int_ptr = new int(3);

Arrays of classes with constructors are initialized with the default constructor. The user-defined new operator with customized initialization plays a key role in C++ constructors for class-type objects.


Overloading the operator new

Example

The global ::operator new() and ::operator new[]() can be overloaded. Each overloaded instance must have a unique signature. Therefore, multiple instances of a global allocation operator can coexist in a single program.

Class-specific memory allocation operators can also be overloaded. The operator new can be implemented to provide alternative free storage (heap) memory-management routines, or implemented to accept additional arguments. A user-defined operator new must return a void* and must have a size_t as its first argument. To overload the new operators, use the following prototypes declared in the new.h header file.

void * operator new(size_t Type_size);    // For Non-array

void * operator new[](size_t Type_size);  // For arrays

The C++Builder compiler provides Type_size to the new operator. Any data type may be substitued for Type_size except function names (although a pointer to function is permitted), class declarations, enumeration declarations, const, volatile.


Overloading the Operator delete

Example

The global operators, ::operator delete(), and ::operator delete[]() cannot be overloaded. However, you can override the default version of each of these operators with your own implementation. Only one instance of the each global delete function can exist in the program.

The user-defined operator delete must have a void return type and void* as its first argument; a second argument of type size_t is optional. A class T can define at most one version of each of T::operator delete[]() and T::operator delete(). To overload the delete operators, use the following prototypes.

void operator delete(void *Type_ptr, [size_t Type_size]);     // For Non-array

void operator delete[](size_t Type_ptr, [size_t Type_size]);  // For arrays


Example of overloading new and delete

#include <stdlib.h>

class X {

   .

   .

   .

public:

   void* operator new(size_t size) { return newalloc(size);}

   void operator delete(void* p) { newfree(p); }

   X() { /* initialize here */ }

   X(char ch) { /* and here */ }

   ~X() { /* clean up here */ }

   .

   .

   .

};

Note: If an exception is thrown, destructors are called if you use the -xd compiler option.

The size argument gives the size of the object being created, and newalloc and newfree are user-supplied memory allocation and deallocation functions. Constructor and destructor calls for objects of class X (or objects of classes derived from X that do not have their own overloaded operators new and delete) will invoke the matching user-defined X::operator new() and X::operator delete(), respectively. (Destructors will be called only if you use the -xd compiler option and an exception is thrown.)

The X::operator new(), X::operator new[](), X::operator delete() and X::operator delete[]() operator functions are static members of X whether explicitly declared as static or not, so they cannot be virtual functions.

The standard, predefined (global) ::operator new(), ::operator new[](), :: operator delete(), and ::operator delete[]() operators can still be used within the scope of X, either explicitly with the global scope or implicitly when creating and destroying non-X or non-X-derived class objects. For example, you could use the standard new and delete when defining the overloaded versions:

void* X::operator new(size_t s)

{

   void* ptr = new char[s]; // standard new called

     .

     .

     .

   return ptr;

}

void X::operator delete(void* ptr)

{

     .

     .

     .

   delete (void*) ptr;     // standard delete called

}

The reason for the size argument is that classes derived from X inherit the X::operator new() and X::operator new[](). The size of a derived class object may well differ from that of the base class.


C++ classes
Classes

See also

C++ classes offer extensions to the predefined type system. Each class type represents a unique set of objects and the operations (methods) and conversions available to create, manipulate, and destroy such objects. Derived classes can be declared that inherit the members of one or more base (or parent) classes.

In C++, structures and unions are considered classes with certain access defaults.

A simplified, “first-look” syntax for class declarations is

class-key <type-info> class-name

<: base-list> { <member-list> };

class-key is one of class, struct, or union.

The optional type-info indicates a request for run-time type information about the class. You can compile with the –RT compiler option, or you can use the __rtti keyword.

The optional base-list lists the base class or classes from which the class class-name will derive (or inherit) objects and methods. If any base classes are specified, the class class-name is called a derived class. The base-list has default and optional overriding access specifiers that can modify the access rights of the derived class to members of the base classes.

The optional member-list declares the class members (data and functions) of class-name with default and optional overriding access specifiers that can affect which functions can access which members.


VCL class declarations

See also	Example	Keywords

Syntax

__declspec(<decl-modifier>)

Description

The decl-modifier argument can be delphiclass or pascalimplementation. These arguments should be used only with classes derived from VCL classes.

You must use  __declspec(delphiclass) for any forward declaration of classes that are directly or indirectly derived from TObject.

Use the __declspec(pascalimplementation) modifier to indicate that a class has been implemented in Object Pascal. This modifier appears in a Pascal portability header file with a .hpp extension.

Note:	another argument, delphireturn, is used internally to mark C++ classes for VCL-compatible handling in function calls as parameters and return values.

The delphiclass argument is used to create classes that have the following VCL compatibility.

VCL-compatible RTTI

VCL-compatible constructor/destructor behavior

VCL-compatible exception handling

A VCL-compatible class has the following restrictions.

No virtual base classes or multiple inheritance is allowed.

Must be dynamically allocated by using the global new operator.

Copy and assignment constructors must be explicitly defined. The compiler does not automatically provide these constructors for VCL-derived classes.


VCL class names

See also	Keywords

The C++Builder IDE expects each VCL class to begin with the letter “T”. Therefore, the first T is always ignored when assigning the program id. For example, a class Test declaration, results in a program id without the leading T.


Class names

See also

class-name is any identifier unique within its scope. With structures, classes, and unions, class-name can be omitted. See Untagged structures and typedefs for discussion of untagged structures.


Class types

See also

The declaration creates a unique type, class type class-name. This lets you declare further class objects (or instances) of this type, and objects derived from this type (such as pointers to, references to, arrays of class-name, and so on):

class X { ... };

X x, &xr, *xptr, xarray[10];

/* four objects: type X, reference to X, pointer to X and array of X */

struct Y { ... };

Y y, &yr, *yptr, yarray[10];

// C would have

// struct Y y, *yptr, yarray[10];

union Z { ... };

Z z, &zr, *zptr, zarray[10];

// C would have

// union Z z, *zptr, zarray[10];

Note the difference between C and C++ structure and union declarations: The keywords struct and union are essential in C, but in C++, they are needed only when the class names, Y and Z, are hidden (see Class name scope)


Class name scope

See also

The scope of a class name is local. There are some special requirements if the class name appears more than once in the same scope. Class name scope starts at the point of declaration and ends with the enclosing block. A class name hides any class, object, enumerator, or function with the same name in the enclosing scope. If a class name is declared in a scope containing the declaration of an object, function, or enumerator of the same name, the class can be referred to only by using the elaborated type specifier. This means that the class key, class, struct, or union, must be used with the class name. For example,

struct S { ... };

int S(struct S *Sptr);

void func(void) {

   S t;         // ILLEGAL declaration: no class key and function S in scope

   struct S s;  // OK: elaborated with class key

   S(&s);       // OK: this is a function call

}

C++ also allows a forward class declaration:

class X;  // no members, yet!

Forward declarations permit certain references to class name X (usually references to pointers to class objects) before the class has been fully defined. See Structure member declarations for more information. Of course, you must make a complete class declaration with members before you can define and use class objects.

Forward declarations cannot be made for typedef classes.

See also the syntax for forward declarations of VCL classes.


Class objects

See also

Class objects can be assigned (unless copying has been restricted), passed as arguments to functions, returned by functions (with some exceptions), and so on. Other operations on class objects and members can be user-defined in many ways, including definition of member and friend functions and the redefinition of standard functions and operators when used with objects of a certain class.

Redefined functions and operators are said to be overloaded. Operators and functions that are restricted to objects of a certain class (or related group of classes) are called member functions for that class. C++ offers the overloading mechanism that allows the same function or operator name can be called to perform different tasks, depending on the type or number of arguments or operands.


Class member list

See also

The optional member-list is a sequence of data declarations (of any type, including enumerations, bit fields and other classes), function declarations, and definitions, all with optional storage class specifiers and access modifiers. The objects thus defined are called class members. The storage class specifiers auto, extern, and register are not allowed. Members can be declared with the static storage class specifiers.


Member functions;methods
Member functions

See also	Example

A function declared without the friend specifier is known as a member function of the class. Functions declared with the friend modifier are called friend functions.

Member functions are often referred to as methods in Object Pascal and Delphi documentation.

The same name can be used to denote more than one function, provided they differ in argument type or number of arguments.


Member function access

/* Getting access to member functions of a base class. */

#include <iostream.h>

class X {

public:

   void func1() {cout << "func1" << endl; }

};

class Y : public X {

public:

   void func2()

   {

    cout << "func2" << endl;

    }

};

void main() {

 X myX;

 Y *myY = new Y;

   myX.func1();

   myY ->func2();  // Member function

   myY ->func1();  // Member function in base class

}


The keyword this

See also

Nonstatic member functions operate on the class type object they are called with. For example, if x is an object of class X and f() is a member function of X, the function call x.f() operates on x. Similarly, if xptr is a pointer to an X object, the function call xptr->f() operates on *xptr. But how does f know which instance of X it is operating on? C++ provides f with a pointer to x called this. this is passed as a hidden argument in all calls to nonstatic member functions.

this is a local variable available in the body of any nonstatic member function. this does not need to be declared and is rarely referred to explicitly in a function definition. However, it is used implicitly within the function for member references. If x.f(y) is called, for example, where y is a member of X, this is set to &x and y is set to this->y, which is equivalent to x.y.


Static members

See also

The storage class specifier static can be used in class declarations of data and function members. Such members are called static members and have distinct properties from nonstatic members. With nonstatic members, a distinct copy “exists” for each instance of the class; with static members, only one copy exists, and it can be accessed without reference to any particular object in its class. If x is a static member of class X, it can be referenced as X::x (even if objects of class X haven’t been created yet). It is still possible to access x using the normal member access operators. For example, y.x and yptr->x, where y is an object of class X and yptr is a pointer to an object of class X, although the expressions y and yptr are not evaluated. In particular, a static member function can be called with or without the special member function syntax:

class X {

   int member_int;

public:

   static void func(int i, X* ptr);

};

void g(void); {

   X obj;

   func(1, &obj);      // error unless there is a global func()

                       // defined elsewhere

   X::func(1, &obj);   // calls the static func() in X

                       // OK for static functions only

   obj.func(1, &obj);  // so does this (OK for static and

                       // nonstatic functions)

}

Because static member functions can be called with no particular object in mind, they don’t have a this pointer, and therefore cannot access nonstatic members without explicitly specifying an object with . or ->. For example, with the declarations of the previous example, func might be defined as follows:

void X::func(int i, X* ptr)

{

   member_int = i;       // which object does member_int

                         // refer to? Error

   ptr->member_int = i;  // OK: now we know!

}

Apart from inline functions, static member functions of global classes have external linkage. Static member functions cannot be virtual functions. It is illegal to have a static and nonstatic member function with the same name and argument types.

The declaration of a static data member in its class declaration is not a definition, so a definition must be provided elsewhere to allocate storage and provide initialization.

Static members of a class declared local to some function have no linkage and cannot be initialized. Static members of a global class can be initialized like ordinary global objects, but only in file scope. Static members, nested to any level, obey the usual class member access rules, except they can be initialized.

class X {

   static int x;

   static const int size =  5;

   class inner {

      static float f;

      void func(void);     // nested declaration

      };

public :

   char array[size];

};

int X::x = 1;

float X::inner::f = 3.14;  // initialization of nested static

void X::inner::func(void) {     /*  define the nested function */  }

The principal use for static members is to keep track of data common to all objects of a class, such as the number of objects created, or the last-used resource from a pool shared by all such objects. Static members are also used to

 	Reduce the number of visible global names

 	Make obvious which static objects logically belong to which class

 	Permit access control to their names


Inline functions

See also

You can declare a member function within its class and define it elsewhere. Alternatively, you can both declare and define a member function within its class, in which case it is called an inline function.

C++Builder can sometimes reduce the normal function call overhead by substituting the function call directly with the compiled code of the function body. This process, called an inline expansion of the function body, does not affect the scope of the function name or its arguments. Inline expansion is not always possible or feasible. The inline specifier indicates to the compiler you would like an inline expansion.

Note:	The C++Builder compiler can ignore requests for inline expansion.

Explicit and implicit inline requests are best reserved for small, frequently used functions, such as the operator functions that implement overloaded operators. For example, the following class declaration of func:

int i;                          // global int

class X {

public:

   char* func(void) { return i; }  // inline by default

   char* i;

};

is equivalent to:

inline char* X::func(void) { return i; }

func is defined outside the class with an explicit inline specifier. The i returned by func is the char* i of class X (see Member scope).

Inline functions and exceptions

An inline function with an exception-specification will never be expanded inline by C++Builder. For example,

inline void f1() throw(int)

   {

   // Warning: Functions with exception specifications are not expanded inline

   }

The remaining restrictions apply only when destructor cleanup is enabled.

Note:	Destructors are called by default. See Setting exception handling options for information about exception-handling switches.

An inline function that takes at least one parameter that is of type ’class with a destructor’ will not be expanded inline. Note that this restriction does not apply to classes that are passed by reference. Example:

struct foo {

   foo();

   ~foo();

   };

inline void f2(foo& x) {

   // no warning, f2() can be expanded inline

   }

inline void f3(foo x) {

   // Warning: Functions taking class-by-value argument(s) are

   //          not expanded inline in function f3(foo)

   }

An inline function that returns a class with a destructor by value will not be expanded inline whenever there are variables or temporaries that need to be destructed within the return expression:

struct foo {

   foo();

   ~foo();

   };

inline foo f4() {

   return foo();

   // no warning, f4() can be expanded inline

   }

inline foo f5() {

   foo X;

   return foo(); // Object X needs to be destructed

   // Warning: Functions containing some return statements are

   //          not expanded inline in function f5()

   }

inline foo f6() {

   return ( foo(), foo() );  // temporary in return value

   // Warning:	Functions containing some return statements are

   //         	not expanded inline in function f6()

   }


Member scope

See also

The expression X::func() in the example in Inline functions and exceptions uses the class name X with the scope access modifier to signify that func, although defined “outside” the class, is indeed a member function of X and exists within the scope of X. The influence of X:: extends into the body of the definition. This explains why the i returned by func refers to X::i, the char* i of X, rather than the global int i. Without the X:: modifier, the function func would represent an ordinary non-class function, returning the global int i.

All member functions, then, are in the scope of their class, even if defined outside the class.

Data members of class X can be referenced using the selection operators . and -> (as with C structures). Member functions can also be called using the selection operators (see The keyword this). For example:

class X {

public:

   int i;

   char name[20];

   X *ptr1;

   X *ptr2;

   void Xfunc(char*data, X* left, X* right);   // define elsewhere

};

void f(void);

{

   X x1, x2, *xptr=&x1;

   x1.i = 0;

   x2.i = x1.i;

   xptr–>i = 1;

   x1.Xfunc("stan", &x2, xptr);

}

If m is a member or base member of class X, the expression X::m is called a qualified name; it has the same type as m, and it is an lvalue only if m is an lvalue. It is important to note that, even if the class name X is hidden by a non-type name, the qualified name X::m will access the correct class member, m.

Class members cannot be added to a class by another section of your program. The class X cannot contain objects of class X, but can contain pointers or references to objects of class X (note the similarity with C’s structure and union types).


Nested types

See also

Tag or typedef names declared inside a class lexically belong to the scope of that class. Such names can, in general, be accessed only by using the xxx::yyy notation, except when in the scope of the appropriate class.

A class declared within another class is called a nested class. Its name is local to the enclosing class; the nested class is in the scope of the enclosing class. This is a purely lexical nesting. The nested class has no additional privileges in accessing members of the enclosing class (and vice versa).

Classes can be nested in this way to an arbitrary level, up to the limits of memory. Nested classes can be declared inside some class and defined later. For example,

struct outer

{

   typedef int t;  // 'outer::t' is a typedef name

   struct inner    // 'outer::inner' is a class

   {

      static int x;

   };

   static int x;

      int f();

   class deep;     // nested declaration

};

int outer::x;     // define static data member

int outer::f() {

   t x;           // 't' visible directly here

   return x;

   }

int outer::inner::x;    // define static data member

outer::t x;             //  have to use 'outer::t' here

class outer::deep { };  // define the nested class here

With Borland C++ 2.0, any tags or typedef names declared inside a class actually belong to the global (file) scope. For example:

struct foo

{

   enum bar { x };   // 2.0 rules: 'bar' belongs to file scope

                     // 2.1 rules: 'bar' belongs to 'foo' scope

};

bar x;

The preceding fragment compiles without errors. But because the code is illegal under the 2.1 rules, a warning is issued as follows:

Warning: Use qualified name to access nested type 'foo::bar'


Member access control

See also

Members of a class acquire access attributes either by default (depending on class key and declaration placement) or by the use of one of the three access specifiers: public, private, and protected. The significance of these attributes is as follows:

public: The member can be used by any function.

private: The member can be used only by member functions and friends of the class it’s declared in.

protected: Same as for private. Additionally, the member can be used by member functions and friends of classes derived from the declared class, but only in objects of the derived type. (Derived classes are explained in Base and derived class access.)

Note:	Friend function declarations are not affected by access specifiers (see Friends of classes for more information).

Members of a class are private by default, so you need explicit public or protected access specifiers to override the default.

Members of a struct are public by default, but you can override this with the private or protected access specifier.

Members of a union are public by default; this cannot be changed. All three access specifiers are illegal with union members.

A default or overriding access modifier remains effective for all subsequent member declarations until a different access modifier is encountered. For example,

class X {

   int i;    // X::i is private by default

   char ch;  // so is X::ch

public:

   int j;    // next two are public

   int k;

protected:

   int l;    // X::l is protected

};

struct Y {

   int i;    // Y::i is public by default

private:

   int j;    // Y::j is private

public:

   int k;    // Y::k is public

};

union Z {

   int i;    // public by default; no other choice

   double d;

};

Note:	The access specifiers can be listed and grouped in any convenient sequence. You can save typing effort by declaring all the private members together, and so on.


Base and derived class access

See also

When you declare a derived class D, you list the base classes B1, B2, ... in a comma-delimited base-list:

class-key D : base-list { <member-list> }

D inherits all the members of these base classes. (Redefined base class members are inherited and can be accessed using scope overrides, if needed.) D can use only the public and protected members of its base classes. But, what will be the access attributes of the inherited members as viewed by D? D might want to use a public member from a base class, but make it private as far as outside functions are concerned. The solution is to use access specifiers in the base-list.

Note:	Since a base class can itself be a derived class, the access attribute question is recursive: you backtrack until you reach the basest of the base classes, those that do not inherit.

When declaring D, you can use the access specifier public, protected, or private in front of the classes in the base-list:

class D : public B1, private B2, ... {

  .

  .

  .

}

These modifiers do not alter the access attributes of base members as viewed by the base class, though they can alter the access attributes of base members as viewed by the derived class.

The default is private if D is a class declaration, and public if D is a struct declaration.

Note:	Unions cannot have base classes, and unions cannot be used as base classes.

The derived class inherits access attributes from a base class as follows:

 	public base class: public members of the base class are public members of the derived class. protected members of the base class are protected members of the derived class. private members of the base class remain private to the base class.

 	protected base class: Both public and protected members of the base class are protected members of the derived class. private members of the base class remain private to the base class.

 	private base class: Both public and protected members of the base class are private members of the derived class. private members of the base class remain private to the base class.

Note that private members of a base class are always inaccessible to member functions of the derived class unless friend declarations are explicitly declared in the base class granting access. For example,

/* class X is derived from class A */

class X : A {               // default for class is private A

  .

  .

  .

}

/* class Y is derived (multiple inheritance) from B and C

   B defaults to private B */

class Y : B, public C {     // override default for C

  .

  .

  .

}

/* struct S is derived from D */

struct S : D {              // default for struct is public D

  .

  .

  .

}

/* struct T is derived (multiple inheritance) from D and E

   E defaults to public E */

struct T : private D, E {   // override default for D

                            // E is public by default

  .

  .

  .

}

The effect of access specifiers in the base list can be adjusted by using a qualified-name in the public or protected declarations of the derived class. For example:

class B {

   int a;               // private by default

public:

   int b, c;

   int Bfunc(void);

};

class X : private B {   // a, b, c, Bfunc are now private in X

   int d;               // private by default, NOTE: a is not

                        // accessible in X

public:

   B::c;                // c was private, now is public

   int e;

   int Xfunc(void);

};

int Efunc(X& x);        // external to B and X

The function Efunc() can use only the public names c, e, and Xfunc().

The function Xfunc() is in X, which is derived from private B, so it has access to

 	The “adjusted-to-public” c

 	The “private-to-X” members from B: b and Bfunc()

 	X’s own private and public members: d, e, and Xfunc()

However, Xfunc() cannot access the “private-to-B” member, a.


Virtual base classes

See also

A virtual class is a base class that is passed to more than one derived class, as might happen with multiple inheritance.

You cannot specify a base class more than once in a derived class:

class B { ...};

class D : B, B { ... };  // ILLEGAL

However, you can indirectly pass a base class to the derived class more than once:

class X : public B { ... }

class Y : public B { ... }

class Z : public X, public Y { ... }  // OK

In this case, each object of class Z has two sub-objects of class B.

If this causes problems, add the keyword virtual to the base class specifier. For example,

class X : virtual public B { ... }

class Y : virtual public B { ... }

class Z : public X, public Y { ... }

B is now a virtual base class, and class Z has only one sub-object of class B.

Constructors for Virtual Base Classes

Constructors for virtual base classes are invoked before any non-virtual base classes.

If the hierarchy contains multiple virtual base classes, the virtual base class constructors invoke in the order they were declared.

Any non-virtual bases are then constructed before the derived class constructor is called.

If a virtual class is derived from a non-virtual base, that non-virtual base will be first, so that the virtual base class can be properly constructed. For example, this code

class X : public Y, virtual public Z

   X one;

produces this order:

Z();   // virtual base class initialization

Y();   // non-virtual base class

X();   // derived class


Friends of classes

See also

A friend F of a class X is a function or class, although not a member function of X, with full access rights to the private and protected members of X. In all other respects, F is a normal function with respect to scope, declarations, and definitions.

Since F is not a member of X, it is not in the scope of X, and it cannot be called with the x.F and xptr->F selector operators (where x is an X object and xptr is a pointer to an X object).

If the specifier friend is used with a function declaration or definition within the class X, it becomes a friend of X.

friend functions defined within a class obey the same inline rules as member functions (see Inline functions). friend functions are not affected by their position within the class or by any access specifiers. For example:

class X {

   int i;                           // private to X

   friend void friend_func(X*, int);

/* friend_func is not private, even though it's declared in the private section */

public:

     void member_func(int);

};

/* definitions; note both functions access private int i */

void friend_func(X* xptr, int a) { xptr–>i = a; }

void X::member_func(int a) { i = a; }

X xobj;

/* note difference in function calls */

friend_func(&xobj, 6);

xobj.member_func(6);

You can make all the functions of class Y into friends of class X with a single declaration:

class Y;                      // incomplete declaration

class X {

   friend Y;

   int i;

   void member_funcX();

};

class Y; {                    // complete the declaration

   void friend_X1(X&);

   void friend_X2(X*);

.

.

.

};

The functions declared in Y are friends of X, although they have no friend specifiers. They can access the private members of X, such as i and member_funcX.

It is also possible for an individual member function of class X to be a friend of class Y:

class X {

.

.

.

   void member_funcX();

}

class Y {

   int i;

   friend void X::member_funcX();

.

.

.

};

Class friendship is not transitive: X friend of Y and Y friend of Z does not imply X friend of Z. Friendship is not inherited.


Constructors and destructors
Introduction to constructors and destructors

See also

There are several special member functions that determine how the objects of a class are created, initalized, copied, and destroyed. Constructors and destructors are the most important of these. They have many of the characteristics of normal member functions—you declare and define them within the class, or declare them within the class and define them outside—but they have some unique features:

 	They do not have return value declarations (not even void).

 	They cannot be inherited, though a derived class can call the base class’s constructors and destructors.

 	Constructors, like most C++ functions, can have default arguments or use member initialization lists.

 	Destructors can be virtual, but constructors cannot. (See Virtual destructors.)

You can’t take their addresses.

int main (void)

{

.

.

.

void *ptr = base::base;    // illegal

.

.

.

}

 	Constructors and destructors can be generated by C++Builder if they haven’t been explicitly defined; they are also invoked on many occasions without explicit calls in your program. Any constructor or destructor generated by the compiler will be public.

 	You cannot call constructors the way you call a normal function. Destructors can be called if you use their fully qualified name.

{

.

.

.

X *p;

.

.

.

p–>X::~X();                // legal call of destructor

X::X();                    // illegal call of constructor

.

.

.

}

 	The compiler automatically calls constructors and destructors when defining and destroying objects.

 	Constructors and destructors can make implicit calls to operator new and operator delete if allocation is required for an object.

 	An object with a constructor or destructor cannot be used as a member of a union.

 	If no constructor has been defined for some class X to accept a given type, no attempt is made to find other constructors or conversion functions to convert the assigned value into a type acceptable to a constructor for class X. Note that this rule applies only to any constructor with one parameter and no initializers that use the “=” syntax.

class X { /* ... */ X(int); };

class Y { /* ... */ Y(X); };

Y a = 1;                   // illegal: Y(X(1)) not tried

If class X has one or more constructors, one of them is invoked each time you define an object x of class X. The constructor creates x and initializes it. Destructors reverse the process by destroying the class objects created by constructors.

Constructors are also invoked when local or temporary objects of a class are created; destructors are invoked when these objects go out of scope.


Constructors

See also

Constructors are distinguished from all other member functions by having the same name as the class they belong to. When an object of that class is created or is being copied, the appropriate constructor is called implicitly.

Constructors for global variables are called before the main function is called. When the #pragma startup directive is used to install a function prior to the main function, global variable constructors are called prior to the startup functions.

Local objects are created as the scope of the variable becomes active. A constructor is also invoked when a temporary object of the class is created.

class X {

public:

   X();   // class X constructor

};

A class X constructor cannot take X as an argument:

class X {

public:

   X(X);                      // illegal

};

The parameters to the constructor can be of any type except that of the class it’s a member of. The constructor can accept a reference to its own class as a parameter; when it does so, it is called the copy constructor . A constructor that accepts no parameters is called the default constructor .


Constructor defaults

See also

The default constructor for class X is one that takes no arguments; it usually has the form X::X(). If no user-defined constructors exist for a class, C++Builder generates a default constructor. On a declaration such as X x, the default constructor creates the object x.

Like all functions, constructors can have default arguments. For example, the constructor

X::X(int, int = 0)

can take one or two arguments. When presented with one argument, the missing second argument is assumed to be a zero int. Similarly, the constructor

X::X(int = 5, int = 6)

could take two, one, or no arguments, with appropriate defaults. However, the default constructor X::X() takes no arguments and must not be confused with, say, X::X(int = 0), which can be called with no arguments as a default constructor, or can take an argument.

You should avoid ambiguity in defining constructors. In the following case, the two default constructors are ambiguous:

class X

{

public:

   X();

   X(int i = 0);

};

int main() {

   X one(10);  // OK; uses X::X(int)

   X two;      // Error;ambiguous whether to call X::X() or

               // X::X(int = 0)

   return 0;

}


The copy constructor

See also

A copy constructor for class X is one that can be called with a single argument of type X as follows:

X::X(X&)

or

X::X(const X&)

or

X::X(const X&, int = 0)

Default arguments are also allowed in a copy constructor. Copy constructors are invoked when initializing a class object, typically when you declare with initialization by another class object:

X x1;

X x2 = x1;

X x3(x1);

C++Builder generates a copy constructor for class X if one is needed and no other constructor has been defined in class X. The copy constructor that is generated by the C++Builder compiler lets you safely start programming with simple data types. You need to make your own definition of the copy constructor if your program creates aggregate, complex types such as class, struct, and array types. The copy constructor is also called when you pass a class argument by value to a function.

See also the discussion of member-by-member class assignment. You should define the copy constructor if you overload the assignment operator.


Overloading constructors

See also

Constructors can be overloaded, allowing objects to be created, depending on the values being used for initialization.

class X {

   int    integer_part;

   double double_part;

public:

   X(int i)    { integer_part = i; }

   X(double d) { double_part = d; }

};

int main() {

   X one(10);   // invokes X::X(int) and sets integer_part to 10

   X one(3.14); // invokes X::X(double) setting double_part to 3.14

   return 0;

}


Order of calling constructors

See also

In the case where a class has one or more base classes, the base class constructors are invoked before the derived class constructor. The base class constructors are called in the order they are declared.

For example, in this setup,

class Y {...}

class X : public Y {...}

X one;

the constructors are called in this order:

Y();   // base class constructor

X();   // derived class constructor

For the case of multiple base classes,

class X : public Y, public Z

X one;

the constructors are called in the order of declaration:

Y();  // base class constructors come first

Z();

X();

Constructors for virtual base classes are invoked before any nonvirtual base classes. If the hierarchy contains multiple virtual base classes, the virtual base class constructors are invoked in the order in which they were declared. Any nonvirtual bases are then constructed before the derived class constructor is called.

If a virtual class is derived from a nonvirtual base, that nonvirtual base will be first so that the virtual base class can be properly constructed. The code:

class X : public Y, virtual public Z

X one;

produces this order:

Z();   // virtual base class initialization

Y();   // nonvirtual base class

X();   // derived class

Or, for a more complicated example:

class base;

class base2;

class level1 : public base2, virtual public base;

class level2 : public base2, virtual public base;

class toplevel : public level1, virtual public level2;

toplevel view;

The construction order of view would be as follows:

base();      // virtual base class highest in hierarchy

             // base is constructed only once

base2();     // nonvirtual base of virtual base level2

             // must be called to construct level2

level2();    // virtual base class

base2();     // nonvirtual base of level1

level1();    // other nonvirtual base

toplevel();

If a class hierarchy contains multiple instances of a virtual base class, that base class is constructed only once. If, however, there exist both virtual and nonvirtual instances of the base class, the class constructor is invoked a single time for all virtual instances and then once for each nonvirtual occurrence of the base class.

Constructors for elements of an array are called in increasing order of the subscript.


Class initialization

See also

An object of a class with only public members and no constructors or base classes (typically a structure) can be initialized with an initializer list. If a class has a constructor, its objects must be either initialized or have a default constructor. The latter is used for objects not explicitly initialized.

Objects of classes with constructors can be initialized with an expression list in parentheses. This list is used as an argument list to the constructor. An alternative is to use an equal sign followed by a single value. The single value can be the same type as the first argument accepted by a constructor of that class, in which case either there are no additional arguments, or the remaining arguments have default values. It could also be an object of that class type. In the former case, the matching constructor is called to create the object. In the latter case, the copy constructor is called to initialize the object.

class X

{

   int i;

public:

   X();         // function bodies omitted for clarity

   X(int x);

   X(const X&);

};

void main()

{

   X one;        // default constructor invoked

   X two(1);     // constructor X::X(int) is used

   X three = 1;  // calls X::X(int)

   X four = one; // invokes X::X(const X&) for copy

   X five(two);  // calls X::X(const X&)

}

The constructor can assign values to its members in two ways:

 	It can accept the values as parameters and make assignments to the member variables within the function body of the constructor:

class X

{

   int a, b;

public:

   X(int i, int j) { a = i; b = j }

};

 	An initializer list can be used prior to the function body:

class X

{

   int a, b, &c;  // Note the reference variable.

public:

   X(int i, int j) : a(i), b(j), c(a) {}

};

The initializer list is the only place to initialize a reference variable.

In both cases, an initialization of X x(1, 2) assigns a value of 1 to x::a and 2 to x::b. The second method, the initializer list, provides a mechanism for passing values along to base class constructors.

Note:	Base class constructors must be declared as either public or protected to be called from a derived class.

class base1

{

   int x;

public:

   base1(int i) { x = i; }

};

class base2

{

   int x;

public:

   base2(int i) : x(i) {}

};

class top : public base1, public base2

{

   int a, b;

public:

   top(int i, int j) : base1(i*5), base2(j+i), a(i) { b = j;}

};

With this class hierarchy, a declaration of top one(1, 2) would result in the initialization of base1 with the value 5 and base2 with the value 3. The methods of initialization can be intermixed.

As described previously, the base classes are initialized in declaration order. Then the members are initialized, also in declaration order, independent of the initialization list.

class X

{

  int a, b;

public:

  X(int i, j) :  a(i), b(a+j) {}

};

With this class, a declaration of X x(1,1) results in an assignment of 1 to x::a and 2 to x::b.

Base class constructors are called prior to the construction of any of the derived classes members. If the values of the derived class are changed, they will have no effect on the creation of the base class.

class base

{

   int x;

public:

   base(int i) : x(i) {}

};

class derived : base

{

   int a;

public:

   derived(int i) : a(i*10), base(a) { } // Watch out! Base will be

                                         // passed an uninitialized ’a’

};

With this class setup, a call of derived d(1) will not result in a value of 10 for the base class member x. The value passed to the base class constructor will be undefined.

When you want an initializer list in a non-inline constructor, don’t place the list in the class definition. Instead, put it at the point at which the function is defined.

derived::derived(int i) : a(i)

{

  .

  .

  .

}


Destructors

See also

The destructor for a class is called to free members of an object before the object is itself destroyed. The destructor is a member function whose name is that of the class preceded by a tilde (~). A destructor cannot accept any parameters, nor will it have a return type or value declared.

#include <stdlib.h>

class X

{

public:

   ~X(){};  // destructor for class X

};

If a destructor isn’t explicitly defined for a class, the compiler generates one.


Invoking destructors

See also

A destructor is called implicitly when a variable goes out of its declared scope. Destructors for local variables are called when the block they are declared in is no longer active. In the case of global variables, destructors are called as part of the exit procedure after the main function.

When pointers to objects go out of scope, a destructor is not implicitly called. This means that the delete operator must be called to destroy such an object.

Destructors are called in the exact opposite order from which their corresponding constructors were called (see Order of calling constructors).


atexit, #pragma exit, and destructors

See also

All global objects are active until the code in all exit procedures has executed. Local variables, including those declared in the main function, are destroyed as they go out of scope. The order of execution at the end of a C++Builder program is as follows:

 	atexit() functions are executed in the order they were inserted.

 	#pragma exit functions are executed in the order of their priority codes.

 	Destructors for global variables are called.


exit and destructors

See also

When you call exit from within a program, destructors are not called for any local variables in the current scope. Global variables are destroyed in their normal order.


abort and destructors

See also

If you call abort anywhere in a program, no destructors are called, not even for variables with a global scope.

A destructor can also be invoked explicitly in one of two ways: indirectly through a call to delete, or directly by using the destructor’s fully qualified name. You can use delete to destroy objects that have been allocated using new. Explicit calls to the destructor are necessary only for objects allocated a specific address through calls to new

#include <stdlib.h>

class X {

public:

  .

  .

  .

   ~X(){};

  .

  .

  .

};

void* operator new(size_t size, void *ptr)

{

   return ptr;

}

char buffer[sizeof(X)];

void main() {

   X* pointer = new X;

   X* exact_pointer;

   exact_pointer = new(&buffer) X; // pointer initialized at

                                   // address of buffer

.

.

.

   delete pointer;                 // delete used to destroy pointer

   exact_pointer–>X::~X();         // direct call used to deallocate

}


Virtual destructors

See also

A destructor can be declared as virtual. This allows a pointer to a base class object to call the correct destructor in the event that the pointer actually refers to a derived class object. The destructor of a class derived from a class with a virtual destructor is itself virtual.

/* How virtual affects the order of destructor calls.

   Without a virtual destructor in the base class, the derived

   class destructor won't be called. */

#include <iostream.h>

class color {

public:

   virtual ~color() {  // Virtual destructor

      cout << "color dtor\n";

      }

};

class red : public color {

public:

   ~red() {  // This destructor is also virtual

      cout << "red dtor\n";

      }

};

class brightred : public red {

public:

   ~brightred() {  // This destructor is also virtual

       cout << "brightred dtor\n";

       }

};

int main() {

   color *palette[3];

   palette[0] = new red;

   palette[1] = new brightred;

   palette[2] = new color;

   // The destructors for red and color are called.

   delete palette[0];

   cout << endl;

   // The destructors for bright red, red, and color are called.

   delete palette[1];

   cout << endl;

   // The destructor for color is called.

   delete palette[2];

   return 0;

}

Program Output:

red dtor

color dtor

brightred dtor

red dtor

color dtor

color dtor

However, if no destructors are declared as virtual, delete palette[0], delete palette[1], and delete palette[2] would all call only the destructor for class color. This would incorrectly destruct the first two elements, which were actually of type red and brightred.


Overloading Operators

See also	Operators

C++ lets you redefine the actions of most operators, so that they perform specified functions when used with objects of a particular class. As with overloaded C++ functions in general, the compiler distinguishes the different functions by noting the context of the call: the number and types of the arguments or operands.

All the operators can be overloaded except for:

.   .*   ::   ?:

The following preprocessing symbols cannot be overloaded.

 #   ##

The =, [ ], ( ), and -> operators can be overloaded only as nonstatic member functions. These operators cannot be overloaded for enum types. Any attempt to overload a global version of these operators results in a compile-time error.

The keyword operator followed by the operator symbol is called the operator function name; it is used like a normal function name when defining the new (overloaded) action for the operator.

A function operator called with arguments behaves like an operator working on its operands in an expression. The operator function cannot alter the number of arguments or the precedence and associativity rules applying to normal operator use.


Example for Overloading Operators

The following example extends the class complex to create complex-type vectors. Several of the most useful operators are overloaded to provide some customary mathematical operations in the usual mathematical syntax.

Some of the issues illustrated by the example are:

The default constructor is defined. This is provided by the compiler only if you have not defined it or any other constructor.

The copy constructor is defined explicitly. Normally, if you have not defined any constructors, the compiler will provide one. You should define the copy constructor if you are overloading the assignment operator.

The assignment operator is overloaded. If you do not overload the assignment operator, the compiler calls a default assignment operator when required. By overloading assignment of cvector types, you specify exactly the actions to be taken. Note that the assignment operator function cannot be inherited by derived classes

The subscript operator is defined as a member function (a requirement when overloading) with a single argument. The const version assures the caller that it will not modify its argument—this is useful when copying or assigning. This operator should check that the index value is within range—a good place to implement exception handling.

The addition operator is defined as a member function. It allows addition only for cvector types. Addition should always check that the operands’ sizes are compatible.

The multiplication operator is declared a friend. This lets you define the order of the operands. An attempt to reverse the order of the operands is a compile-time error.

The stream insertion operator is overloaded to naturally display a cvector. Large objects that don’t display well on a limited size screen might require a different display strategy.

Source

/* HOW TO EXTEND THE complex CLASS AND OVERLOAD THE REQUIRED OPERATORS. */

#pragma warn -inl     // IGNORE not expanded inline WARNINGS.

#include <complex.h>  // THIS ALREADY INCLUDES iostream.h

// COMPLEX VECTORS

class cvector {

   int size;

   complex *data;

public:

   cvector() { size = 0; data = NULL; };

   cvector(int i = 5) : size(i) {    // DEFAULT VECTOR SIZE.

      data = new complex[size];

      for (int j = 0; j < size; j++)

           data[j] = j + (0.1 * j);  // ARBITRARY INITIALIZATION.

      };

   /* THIS VERSION IS CALLED IN main() */

   complex& operator [](int i) { return data[i]; };

   /* THIS VERSION IS CALLED IN ASSIGNMENT OPERATOR AND COPY THE CONSTRUCTOR */

   const complex& operator [](int i) const { return data[i]; };

   cvector operator +(cvector& A) {  // ADDITION OPERATOR

      cvector result(A.size);  // DO NOT MODIFY THE ORIGINAL

      for (int i = 0; i < size; i++)

          result[i] = data[i] + A.data[i];

      return result;

      };

   /* BECAUSE scalar * vector MULTIPLICATION IS NOT COMMUTATIVE, THE ORDER OF

      THE ELEMENTS MUST BE SPECIFIED. THIS FRIEND OPERATOR FUNCTION WILL ENSURE

      PROPER MULTIPLICATION. */

   friend cvector operator *(int scalar, cvector& A) {

      cvector result(A.size);  // DO NOT MODIFY THE ORIGINAL

      for (int i = 0; i < A.size; i++)

        result.data[i] = scalar * A.data[i];

      return result;

      }

   /* THE STREAM INSERTION OPERATOR. */

   friend ostream& operator <<(ostream& out_data, cvector& C) {

      for (int i = 0; i < C.size; i++)

           out_data << "[" << i << "]=" << C.data[i] << "   ";

      cout << endl;

      return out_data;

      };

   cvector( const cvector &C ) {  // COPY CONSTRUCTOR

      size = C.size;

      data = new complex[size];

      for (int i = 0; i < size; i++)

           data[i] = C[i];

     }

   cvector& operator =(const cvector &C) { // ASSIGNMENT OPERATOR.

      if (this == &C) return *this;

      delete[] data;

      size = C.size;

      data = new complex[size];

      for (int i = 0; i < size; i++)

          data[i] = C[i];

      return *this;

   };

   virtual ~cvector() { delete[] data; }; // DESTRUCTOR

   };

int main(void) { /* A FEW OPERATIONS WITH complex VECTORS. */

   cvector cvector1(4), cvector2(4), result(4);

   // CREATE complex NUMBERS AND ASSIGN THEM TO complex VECTORS

   cvector1[3] = complex(3.3, 102.8);

   cout << "Here is cvector1:" << endl;

   cout << cvector1;

   cvector2[3] = complex(33.3, 81);

   cout << "Here is cvector2:" << endl;

   cout << cvector2;

   result = cvector1 + cvector2;

   cout << "The result of vector addition:" << endl;

   cout << result;

   result = 10 * cvector2;

   cout << "The result of 10 * cvector2:" << endl;

   cout << result;

   return 0;

   }

Output

Here is cvector1:

[0]=(0, 0)   [1]=(1.1, 0)   [2]=(2.2, 0)   [3]=(3.3, 102.8)

Here is cvector2:

[0]=(0, 0)   [1]=(1.1, 0)   [2]=(2.2, 0)   [3]=(33.3, 81)

The result of vector addition:

[0]=(0, 0)   [1]=(2.2, 0)   [2]=(4.4, 0)   [3]=(36.6, 183.8)

The result of 10 * cvector2:

[0]=(0, 0)   [1]=(11, 0)   [2]=(22, 0)   [3]=(333, 810)


Overloading Operator Functions

See also	Operators

Operator functions can be called directly, although they are usually invoked indirectly by the use of the overload operator:

c3 = c1.operator + (c2);   // same as c3 = c1 + c2

Apart from new and delete, which have their own rules, an operator function must either be a nonstatic member function or have at least one argument of class type. The operator functions =, ( ), [ ] and -> must be nonstatic member functions.

Enumerations can have overloaded operators. However, the operator functions =, ( ), [ ], and -> cannot be overloaded for enumerations.


Overloaded Operators and Inheritance

See also	Operators

With the exception of the assignment function operator =( ), all overloaded operator functions for class X are inherited by classes derived from X, with the standard resolution rules for overloaded functions. If X is a base class for Y, an overloaded operator function for X could possibly be further overloaded for Y.


Overloading Unary Operators

See also	Operators

You can overload a prefix or postfix unary operator by declaring a nonstatic member function taking no arguments, or by declaring a nonmember function taking one argument. If @ represents a unary operator, @x and x@ can both be interpreted as either x.operator@() or operator@(x), depending on the declarations made. If both forms have been declared, standard argument matching is applied to resolve any ambiguity.

Under C++ 2.0, an overloaded operator ++ or -- is used for both prefix and postfix uses of the operator.

With C++ 2.1, when an operator++ or operator- - is declared as a member function with no parameters, or as a nonmember function with one parameter, it only overloads the prefix operator++ or operator- -. You can only overload a postfix operator++ or operator- - by defining it as a member function taking an int parameter or as a nonmember function taking one class and one int parameter.

When only the prefix version of an operator++ or operator- - is overloaded and the operator is applied to a class object as a postfix operator, the compiler issues a warning. Then it calls the prefix operator, allowing 2.0 code to compile. The preceding example results in the following warnings:

Warning: Overloaded prefix 'operator ++' used as a postfix operator in function func()

Warning: Overloaded prefix 'operator --' used as a postfix operator in function func()


Overloading Binary Operators

See also	Operators

You can overload a binary operator by declaring a nonstatic member function taking one argument, or by declaring a non-member function (usually friend) taking two arguments. If @ represents a binary operator, x@y can be interpreted as either x.operator@(y) or operator@(x,y) depending on the declarations made. If both forms have been declared, standard argument matching is applied to resolve any ambiguity.


Overloading the Assignment Operator  =

See also	Operators

The assignment operator=( ) can be overloaded by declaring a nonstatic member function. For example,

class String {

     .

     .

     .

   String& operator = (String& str);

     .

     .

     .

   String (String&);

   ~String();

}

This code, with suitable definitions of String::operator =(), allows string assignments str1 = str2 in the usual sense. Unlike the other operator functions, the assignment operator function cannot be inherited by derived classes. If, for any class X, there is no user-defined operator =, the operator = is defined by default as a member-by-member assignment of the members of class X:

X& X::operator = (const X& source)

{

   // memberwise assignment

}


Overloading the Function Call Operator  ( )

See also	Operators

Syntax

postfix-expression ( <expression-list> )

Description

In its ordinary use as a function call, the postfix-expression must be a function name, or a pointer or reference to a function. When the postfix-expression is used to make a member function call, postfix-expression must be a class member function name or a pointer-to-member expression used to select a class member function. In either case, the postfix-expression is followed by the optional expression-list.

A call X(arg1, arg2), where X is an object class X, is interpreted as X.operator()(arg1, arg2).

The function call operator, operator()(), can only be overloaded as a nonstatic member function.


Overloading the Subscript Operator  [ ]

Syntax

postfix-expression [ expression ]

Description

The corresponding operator function is operator[]() this can be user-defined for a class X (and any derived classes). The expression X[y], where X is an object of class X, is interpreted as x.operator[](y).

The operator[]() can only be overloaded as a nonstatic member function.


Overloading the Class Member Access Operators ->
Overloading the Class Member Access Operator  ->

See also	Operators

Syntax

postfix-expression -> primary-expression

Description

The expression x->m, where x is a class X object, is interpreted as (x.operator->())->m, so that the function operator->() must either return a pointer to a class object or return an object of a class for which operator-> is defined.

The operator->() can only be overloaded as a nonstatic member function.


Polymorphic classes

See also

Classes that provide an identical interface, but can be implemented to serve different specific requirements, are referred to as polymorphic classes. A class is polymorphic if it declares or inherits at least one virtual (or pure virtual) function. The only types that can support polymorphism are class and struct.


Virtual functions

See also

virtual functions allow derived classes to provide different versions of a base class function. You can use the virtual keyword to declare a virtual function in a base class. By declaring the function prototype in the usual way and then prefixing the declaration with the virtual keyword. To declare a pure function (which automatically declares an abstract class), prefix the prototype with the virtual keyword, and set the function equal to zero.

virtual int funct1(void);       // A virtual function declaration.

virtual int funct2(void) = 0;   // A pure function declaration.

virtual void funct3(void) = 0 { // This is a valid declaration.

   // Some code here.

   };

Note:	See Abstract classes for a discussion of pure virtual functions.

When you declare virtual functions, keep these guidelines in mind:

 	They can be member functions only.

 	They can be declared a friend of another class.

 	They cannot be a static member.

A virtual function does not need to be redefined in a derived class. You can supply one definition in the base class so that all calls will access the base function.

To redefine a virtual function in any derived class, the number and type of arguments must be the same in the base class declaration and in the derived class declaration. (The case for redefined virtual functions differing only in return type is discussed below.) A redefined function is said to override the base class function.

You can also declare the functions int Base::Fun(int) and int Derived::Fun(int) even when they are not virtual. In such a case, int Derived::Fun(int) is said to hide any other versions of Fun(int) that exist in any base classes. In addition, if class Derived defines other versions of Fun(), (that is, versions of Fun() with different signatures) such versions are said to be overloaded versions of Fun().

Virtual function return types

Generally, when redefining a virtual function, you cannot change just the function return type. To redefine a virtual function, the new definition (in some derived class) must exactly match the return type and formal parameters of the initial declaration. If two functions with the same name have different formal parameters, C++ considers them different, and the virtual function mechanism is ignored.

However, for certain virtual functions in a base class, their overriding version in a derived class can have a return type that is different from the overridden function. This is possible only when both of the following conditions are met:

 	The overridden virtual function returns a pointer or reference to the base class.

 	The overriding function returns a pointer or reference to the derived class.

If a base class B and class D (derived publicly from B) each contain a virtual function vf, then if vf is called for an object d of D, the call made is D::vf(), even when the access is via a pointer or reference to B. For example,

struct X {};	// Base class.

struct Y : X {};	// Derived class.

struct B {

   virtual void vf1();

   virtual void vf2();

   virtual void vf3();

   void f();

   virtual X* pf();	// Return type is a pointer to base. This can

  	//  be overridden.

   };

class D : public B {

public:

   virtual void vf1();	// Virtual specifier is legal but redundant.

   void vf2(int);	// Not virtual, since it's using a different

 	//  arg list. This hides B::vf2().

// char vf3();	// Illegal: return-type-only change!

   void f();

   Y*   pf();	// Overriding function differs only

   	//  in return type. Returns a pointer to

 	//  the derived class.

   };

void extf() {

   D d;	// Instantiate D

   B* bp = &d;	// Standard conversion from D* to B*

  	// Initialize bp with the table of functions

// provided for object d. If there is no entry for a

  	// function in the d-table, use the function

     	//  in the B-table.

   bp–>vf1();  // Calls D::vf1

   bp–>vf2();  // Calls B::vf2 since D's vf2 has different args

   bp–>f();    // Calls B::f (not virtual)

   X* xptr = bp–>pf();	// Calls D::pf() and converts the result

   	//  to a pointer to X.

   D* dptr = &d;

   Y* yptr = dptr–>pf();	// Calls D::pf() and initializes yptr.

   	//  No further conversion is done.

   }

The overriding function vf1 in D is automatically virtual. The virtual specifier can be used with an overriding function declaration in the derived class. If other classes will be derived from D, the virtual keyword is required. If no further classes will be derived from D, the use of virtual is redundant.

The interpretation of a virtual function call depends on the type of the object it is called for; with nonvirtual function calls, the interpretation depends only on the type of the pointer or reference denoting the object it is called for.

virtual functions exact a price for their versatility: each object in the derived class needs to carry a pointer to a table of functions in order to select the correct one at run time (late binding).


Dynamic functions

See also

dynamic functions are allowed for classes derived from TObject. Dynamic functions are similar to virtual functions except for the way they are stored in the virtual tables. Virtual functions occupy a slot in the virtual table in the object they are defined in, and in the virtual table of every descendant of that object. Dynamic functions occupy a slot in every object that defines them, not in any descendants. That is, dynamic functions are virtual functions stored in sparse virtual tables. If you call a dynamic function, and that function is not defined in your object, the virtual tables of its ancestors are searched until the function is found.

Therefore, dynamic functions reduces the size of your virtual tables at the expense of a delay at runtime to look up the address of the functions.

Because dynamic functions are available only in classes derived from TObject, you will get an error if you use them in a regular class. For example:

class dynfunc

{

int __declspec(dynamic) bar() { return 5; }

};

gives the syntax error, “Error: Storage class 'dynamic' is not allowed here.” But, the following code compiles.

#include <vcl.h>

#include <stdio.h>

class __declspec(delphiclass) func1 : public TObject

{

public:

func1() {	}

int virtual virtbar() { return 5; }

int __declspec(dynamic) dynbar() { return 5; }

};

class __declspec(delphiclass) func2 : public func1

{

public:

func2() {	}

};

class __declspec(delphiclass) func3 : public func2

{

public:

func3() {	}

int virtbar() { return 10; }

int dynbar() { return 10; }

};

int main()

{

func3 * Func3 = new func3;

func1 * Func1 = Func3;

printf("func3->dynbar: %d\n", Func3->dynbar());

printf("func3->virtbar: %d\n", Func3->virtbar());

printf("func1->dynbar: %d\n", Func1->dynbar());

printf("func1->virtbar: %d\n", Func1->virtbar());

delete Func3;

func2 * Func2 = new func2;

printf("func2->dynbar: %d\n", Func2->dynbar());

printf("func2->virtbar: %d\n", Func2->virtbar());

delete Func2;

return 0;

}

Dynamic attribute is inherited

Since dynamic functions are just like virtual functions, the dynamic attribute is automatically inherited. You can verify this by running the above example. When you generate assembly output with "bcc32 -S" you can examine the virtual tables of func1, func2, and func3, and you'll see how func2 has NO entry for dynbar, but it does have an entry for virtbar. Still, you can call dynbar in the func2 object:

Output:

func3->dynbar: 10

func3->virtbar: 10

func1->dynbar: 10

func1->virtbar: 10

func2->dynbar: 5

func2->virtbar: 5

Dynamic functions cannot be made virtual, and vice-versa

You cannot redeclare a virtual function to be dynamic; likewise, you cannot redeclare a dynamic function to be virtual. The following example gives errors:

#include <vcl.h>

#include <stdio.h>

class __declspec(vclclass) func1 : public TObject

{

public:

func1() {	}

int virtual virtbar() { return 5; }

int __declspec(dynamic) dynbar() { return 5; }

};

class __declspec(vclclass) func2 : public foo1

{

public:

func2() {	}

int __declspec(dynamic) virtbar() { return 10; }

int virtual dynbar() { return 10; }

};

Error : Cannot override a virtual with a dynamic function

Error : Cannot override a dynamic with a virtual function


Abstract classes

See also

An abstract class is a class with at least one pure virtual function. A virtual function is specified as pure by setting it equal to zero.

An abstract class can be used only as a base class for other classes. No objects of an abstract class can be created. An abstract class cannot be used as an argument type or as a function return type. However, you can declare pointers to an abstract class. References to an abstract class are allowed, provided that a temporary object is not needed in the initialization. For example,

class shape {       // abstract class

   point center;

.

.

.

public:

   where() { return center; }

   move(point p) { center = p; draw(); }

   virtual void rotate(int) = 0; // pure virtual function

   virtual void draw() = 0;      // pure virtual function

   virtual void hilite() = 0;    // pure virtual function

.

.

.

}

shape x;	// ERROR: attempt to create an object of an abstract class

   shape* sptr;	// pointer to abstract class is OK

   shape f();	// ERROR: abstract class cannot be a return type

int g(shape s);	// ERROR: abstract class cannot be a function argument type

shape& h(shape&);	// reference to abstract class as return

 	// value or function argument is OK

Suppose that D is a derived class with the abstract class B as its immediate base class. Then for each pure virtual function pvf in B, if D doesn’t provide a definition for pvf, pvf becomes a pure member function of D, and D will also be an abstract class.

For example, using the class shape previously outlined,

class circle : public shape {	// circle derived from abstract class

   int radius;	// private

public:

   void rotate(int) { }	// virtual function defined: no action

            	//  to rotate a circle

   void draw();      	// circle::draw must be defined somewhere

}

Member functions can be called from a constructor of an abstract class, but calling a pure virtual function directly or indirectly from such a constructor provokes a run-time error.


C++ scope

See also

The lexical scoping rules for C++, apart from class scope, follow the general rules for C, with the proviso that C++, unlike C, permits both data and function declarations to appear wherever a statement might appear. The latter flexibility means that care is needed when interpreting such phrases as “enclosing scope” and “point of declaration.”


Class scope

See also

The name M of a member of a class X has class scope “local to X”; it can be used only in the following situations:

 	In member functions of X

 	In expressions such as x.M, where x is an object of X

 	In expressions such as xptr->M, where xptr is a pointer to an object of X

 	In expressions such as X::M or D::M, where D is a derived class of X

 	In forward references within the class of which it is a member

Names of functions declared as friends of X are not members of X; their names simply have enclosing scope.


Hiding

See also

A name can be hidden by an explicit declaration of the same name in an enclosed block or in a class. A hidden class member is still accessible using the scope modifier with a class name: X::M. A hidden file scope (global) name can be referenced with the unary operator :: (for example, ::g). A class name X can be hidden by the name of an object, function, or enumerator declared within the scope of X, regardless of the order in which the names are declared. However, the hidden class name X can still be accessed by prefixing X with the appropriate keyword: class, struct, or union.

The point of declaration for a name x is immediately after its complete declaration but before its initializer, if one exists.


C++ scoping rules summary

See also

The following rules apply to all names, including typedef names and class names, provided that C++ allows such names in the particular context discussed:

 	The name itself is tested for ambiguity. If no ambiguities are detected within its scope, the access sequence is initiated.

 	If no access control errors occur, the type of the object, function, class, typedef, and so on, is tested.

 	If the name is used outside any function and class, or is prefixed by the unary scope access operator ::, and if the name is not qualified by the binary :: operator or the member selection operators . and ->, then the name must be a global object, function, or enumerator.

 	If the name n appears in any of the forms X::n, x.n (where x is an object of X or a reference to X), or ptr->n (where ptr is a pointer to X), then n is the name of a member of X or the member of a class from which X is derived.

 	Any name that hasn’t been discussed yet and that is used in a static member function must either be declared in the block it occurs in or in an enclosing block, or be a global name. The declaration of a local name n hides declarations of n in enclosing blocks and global declarations of n. Names in different scopes are not overloaded.

 	Any name that hasn’t been discussed yet and that is used in a nonstatic member function of class X must either be declared in the block it occurs in or in an enclosing block, be a member of class X or a base class of X, or be a global name. The declaration of a local name n hides declarations of n in enclosing blocks, members of the function’s class, and global declarations of n. The declaration of a member name hides declarations of the same name in base classes.

 	The name of a function argument in a function definition is in the scope of the outermost block of the function. The name of a function argument in a nondefining function declaration has no scope at all. The scope of a default argument is determined by the point of declaration of its argument, but it can’t access local variables or nonstatic class members. Default arguments are evaluated at each point of call.

 	A constructor initializer (see ctor-initializer in the class declarator syntax in C++Builder declaration syntax,) is evaluated in the scope of the outermost block of its constructor, so it can refer to the constructor’s argument names.


Using Templates

See also

Templates, also called generics or parameterized types, let you construct a family of related functions or classes. These topics introduce the basic concept of templates:

Exporting and importing templates

Template Syntax

Template Body Parsing

Function Templates

Class Templates

Implicit and Explicit Template Functions

Template Compiler Switches


template

See also	Keywords

Category

C++-Specific Keywords

Syntax

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 typename identifier

template-class-name:

   template-name < template-arg-list >

template-arg-list:

   template-arg

   template-arg-list , template-arg

template-arg:

   expression

   type-name

< template-argument-list > declaration

Description

Use templates (also called generics or parameterized types) to construct a family of related functions or classes.


Template body parsing
Template class body parsing

See also

Earlier versions of the compiler didn't check the syntax of a template body unless the template was instantiated. A template body is now parsed immediately when seen like every other declaration.

template <class T> class X : T

{

  Int  j;  // Error: Type name expected in template X<T>

};

Let's assume that Int hasn't yet been defined. This means that Int must be a member of the template argument T. But it also might just be a typing error and should be int instead of Int. Because the compiler can't guess the right meaning it issues an error message.

If you want to access types defined by a template argument you should use a typedef to make your intention clear to the compiler:

template <class T> class X : T

{

  typedef  typename T::Int  Int;

  Int  j;

};

You cannot just write

   typedef   T::Int;

as in earlier versions of the compiler. Not giving the typedef name was acceptable, but this now causes an error message.

All other templates mentioned inside the template body are declared or defined at that point. Therefore, the following example is ill-formed and will not compile:

template <class T> class  X

{

  void f(NotYetDefindedTemplate<T> x);

};

All template definitions must end with a semicolon. Earlier versions of the compiler did not complain if the semicolon was missing.


Function Templates

See also	Using Templates

Consider a function max(x, y) that returns the larger of its two arguments. x and y can be of any type that has the ability to be ordered. But, since C++ is a strongly typed language, it expects the types of the parameters x and y to be declared at compile time. Without using templates, many overloaded versions of max are required, one for each data type to be supported even though the code for each version is essentially identical. Each version compares the arguments and returns the larger.

One way around this problem is to use a macro:

#define max(x,y) ((x > y) ? x : y)

However, using the #define circumvents the type-checking mechanism that makes C++ such an improvement over C. In fact, this use of macros is almost obsolete in C++. Clearly, the intent of max(x, y) is to compare compatible types. Unfortunately, using the macro allows a comparison between an int and a struct, which are incompatible.

Another problem with the macro approach is that substitution will be performed where you don't want it to be. By using a template instead, you can define a pattern for a family of related overloaded functions by letting the data type itself be a parameter:

template <class T> T max(T x, T y){

   return (x > y) ? x : y;

   };

The data type is represented by the template argument <class T>. When used in an application, the compiler generates the appropriate code for the max function according to the data type actually used in the call:

int i;

Myclass a, b;

int j = max(i,0);       // arguments are integers

Myclass m = max(a,b);   // arguments are type Myclass

Any data type (not just a class) can be used for <class T>. The compiler takes care of calling the appropriate operator>(), so you can use max with arguments of any type for which operator>() is defined.


Overriding a Template Function

Using Templates

The previous example is called a function template (or generic function, if you like). A specific instantiation of a function template is called a template function. Template function instantiation occurs when you take the function address, or when you call the function with defined (non-generic) data types. You can override the generation of a template function for a specific type with a non-template function:

#include <string.h>

char *max(char *x, char *y){

   return(strcmp(x,y) > 0) ? x : y;

}

If you call the function with string arguments, it's executed in place of the automatic template function. In this case, calling the function avoided a meaningless comparison between two pointers.

Only trivial argument conversions are performed with compiler-generated template functions.

The argument type(s) of a template function must use all of the template formal arguments. If it doesn't, there is no way of deducing the actual values for the unused template arguments when the function is called.


Implicit and Explicit Template Functions

Using Templates

When doing overload resolution (following the steps of looking for an exact match), the compiler ignores template functions that have been generated implicitly by the compiler.

template<class T> T max(T a, T b){

        return  (a > b) ? a : b;

};

void    f(int i, char c){

        max(i, i);              // calls max(int ,int )

        max(c, c);              // calls max(char,char)

        max(i, c);              // no match for max(int,char)

        max(c, i);              // no match for max(char,int)

}

This code results in the following error messages:

Could not find a match for 'max(int,char)' in function f(int,char)

Could not find a match for 'max(char,int)' in function f(int,char)

If the user explicitly declares a template function, this function, on the other hand, will participate fully in overload resolution. See the example of explicit template function.

When searching for an exact match for template function parameters, trivial conversions are considered to be exact matches. See the example on trivial conversions.

Template functions with derived class pointer or reference arguments are permitted to match their public base classes. See the example of base class referencing.


Class Templates

See also	Using Templates	Example

A class template (also called a generic class or class generator) lets you define a pattern for class definitions. Consider the following example of a vector class (a one-dimensional array). Whether you have a vector of integers or any other type, the basic operations performed on the type are the same (insert, delete, index, and so on). With the element type treated as a type parameter to the class, the system will generate type-safe class definitions on the fly.

As with function templates, an explicit template class specialization can be provided to override the automatic definition for a given type:

class Vector<char *> { ... };

The symbol Vector must always be accompanied by a data type in angle brackets. It cannot appear alone, except in some cases in the original template definition.


Template Arguments

Using Templates

Multiple arguments are allowed as part of the class template declaration. Template arguments can also represent values in addition to data types:

template<class T, int size = 64> class Buffer { ... };

Both non-type template arguments such as size and type arguments can have default values. The value supplied for a non-type template argument must be a constant expression:

const int N = 128;

int i = 256;

Buffer<int, 2*N> b1;// OK

Buffer<float, i> b2;// Error: i is not constant

Since each instantiation of a template class is indeed a class, it receives its own copy of static members. Similarly, template functions get their own copy of static local variables.


Using Angle Brackets in Templates

Using Templates

Be careful when using the right angle bracket character upon instantiation:

Buffer<char, (x > 100 ? 1024 : 64)> buf;

In the preceding example, without the parentheses around the second argument, the > between x and 100 would prematurely close the template argument list.


Using Type-safe Generic Lists in Templates

Using Templates

In general, when you need to write lots of nearly identical things, consider using templates. The problems with the following class definition, a generic list class,

class GList

{

 public:

   void insert( void * );

   void *peek();

    .

    .

    .

};

are that it isn't type-safe and common solutions need repeated class definitions. Since there's no type checking on what gets inserted, you have no way of knowing what results you'll get. You can solve the type-safe problem by writing a wrapper class:

class FooList : public Glist {

 public:

   void insert( Foo *f ) { GList::insert( f ); }

   Foo *peek() { return (Foo *)GList::peek(); }

      .

      .

      .

};

This is type-safe. insert will only take arguments of type pointer-to-Foo or object-derived-from-Foo, so the underlying container will only hold pointers that in fact point to something of type Foo. This means that the cast in FooList::peek() is always safe, and you've created a true FooList. Now, to do the same thing for a BarList, a BazList, and so on, you need repeated separate class definitions. To solve the problem of repeated class definitions and be type-safe, you can once again use templates. See the example for type-safe generic list class. You can also use the Standard Template Library (STL).

By using templates, you can create whatever type-safe lists you want, as needed, with a simple declaration. And there's no code generated by the type conversions from each wrapper class so there's no run-time overhead imposed by this type safety.


Type-safe generic list class definition

template <class T> class List : public GList

{

public:

   void insert( T *t ) { GList::insert( t ); }

   T *peek() { return (T *)GList::peek(); }

    .

    .

    .

};

  // Create a List object of Foo types and name it fList.

  List<Foo> fList;

// Create a List object of Bar types and name it bList.

  List<Bar> bList;

// Create a List object of Baz types and name it zList.

  List<Baz> zList;


Eliminating Pointers in Templates

Using Templates

Another design technique is to include actual objects, making pointers unnecessary. This can also reduce the number of virtual function calls required, since the compiler knows the actual types of the objects. This is beneficial if the virtual functions are small enough to be effectively inlined. It's difficult to inline virtual functions when called through pointers, because the compiler doesn't know the actual types of the objects being pointed to.

template <class T> aBase {

    .

    .

    .

 private:

  T buffer;

};

class anObject : public aSubject, public aBase<aFilebuf> {

    .

    .

    .

};

All the functions in aBase can call functions defined in aFilebuf directly, without having to go through a pointer. And if any of the functions in aFilebuf can be inlined, you'll get a speed improvement, because templates allow them to be inlined.


Template Compiler Switches

Using Templates

The -Jg family of switches control how instances of templates are generated by the compiler. Every template instance encountered by the compiler will be affected by the value of the switch at the point where the first occurrence of that particular instance is seen by the compiler.

For template functions the switch applies to the function instances; for template classes, it applies to all member functions and static data members of the template class. In all cases, this switch applies only to compiler-generated template instances and never to user-defined instances. It can be used, however, to tell the compiler which instances will be user-defined so that they aren't generated from the template.


Using template switches

Using Templates

When using the -Jg family of switches, there are two basic approaches for generating template instances:

Approach 1

Include the function body (for a function template) or member function and static data member definitions (for a template class) in the header file that defines the particular template, and use the default setting of the template switch (-Jg). If some instances of the template are user-defined, the declarations (prototypes, for example) for them should be included in the same header but preceded by #pragma option -Jgx. See the example for template header files.

Approach 2

Compile all of the source files comprising the program with the -Jgx switch (causing external references to templates to be generated). In order to provide the definitions for all of the template instances, add a file (or files) to the program that includes the template bodies (including any user-defined instance definitions), and list all the template instances needed in the rest of the program to provide the necessary public symbol definitions. Compile the file (or files) with the -Jgd switch. See the example for separate file template compilation.


Changes to template generation semantics

Using Templates

Template generation semantics have changed. In Borland C++Builder 1.0, all out-of-line methods for all template instances used by a program were generated. In C++Builder 3.0, only the following are generated:

Those methods which were actually used

Virtual methods of an instance

All methods of explicitly instantiated classes

The advantage of this new behavior is that it results in significantly smaller .OBJs, .LIBs and .EXEs, depending on how heavily you use templates.

Optionally, you can use the ‘-Ja’ switch to generate all methods, (the same behavior as in Borland C++Builder 1.0).

You can also force all of the out-of-line methods of a template instance to be generated by using the explicit template instantiation syntax defined in the ANSI C++ draft. The syntax is:

template class classname<template parameter>;

The following STL example directs the compiler to generate all out-of-line methods for the “list<char>” class, regardless of whether they are referenced by the user’s code:

template class list<char>

You can also explicitly instantiate a single method, or a single static data member of a template class, which means that the method is generated to the .OBJ even though it is not used:

template void classname <template parameter>:: methodname ();


Template header file

// Declare a template function and define it's body.

/* When this header file is included in a C++ source file, the sort template can be used without worrying about how the various instances are generated (with the exception of sort for integer arrays which is a user-defined instance. Its definition must be provided by the user. */

template<class T> void sort (T* array, int size)

{

   // Body of template goes here.

}

// Sorting of integer elements done by user-define instance.

#pragma option -Jgx

extern void sort(int *array, int size);

// Restore the template switch to its original state.

#pragma option -Jg


Separate file template compilation

// In vector.h

template <class elem, int size> class vector

{

   elem * value;

public:

   vector();

   elem & operator [ ] (int index) {

      return value[index];

      }

};

// In main.cpp source file.

#include "vector.h"

/** Let the compiler know that the following template instances will be defined elsewhere. **/

#pragma option -Jgx

// Use two instances of the vector template class.

vector<int, 100> int_100;

vector<char, 10> char_10;

int main( )

{

   return int_100[ 0 ] + char_10[ 0 ];

}

// In template.cpp source file.

#include <string.h>

#include "vector.h"

// Define any template bodies.

template <class elem, int size> vector <elem, size> :: vector()

{

   value = new elem[size];

   memset(value, 0, size * sizeof(elem) );

}

// Generate the necessary instances.

#pragma option -Jgd

typedef vector<int, 100> fake_int_100;

typedef vector<char, 10> fake_char_10;


Exporting and importing templates

See also

The declaration of a template function or template class needs to be sufficiently flexible to allow it to be used in either a DLL or an EXE file. The same template declaration should be available as an import and/or export, or without a modifier. To be completely flexible, the header file template declarations should not use __export or __import modifiers. This allows the user to apply the appropriate modifier at the point of instantiation depending on how the instantiation is to be used.

The following steps demonstrate exporting and importing of templates. The source code is organized in three files. Using the header file, code is generated in the DLL. A DLL library is created and linked to an EXE file.

1.	Exportable/Importable Template Declarations

The header file contains all template class and template function declarations. An export/import version of the templates can be instantiated by defining the appropriate macro at compile time.

2.	Compiling Exportable Templates

Write the source code for a DLL. When compiled, this DLL has reusable export code for templates.

3.	Using ImportTemplates

Now you can write a calling function that uses templates. This file is linked to the DLL. Only objects that are not declared in the header file and which are instantiated in the main function cause the compiler to generate new code. Code for a newly instantiated object is written into MAIN.OBJ file.


Sharing modules between versions of C++Builder or Delphi

Using Delphi forms

Using .pas files in C++Builder

Sharing packages


Using Delphi Forms in C++Builder projects
Using Delphi forms

C++Builder includes a modified version of the Borland Delphi compiler that allows Delphi units and forms to be compiled and linked into C++Builder applications.

To add a Delphi unit to your C++Builder project, use the Add to Project option of the Project menu, or select the “+” icon on the Project Manager window, to open the Add to Project dialog. Select Pascal unit as the File Type and select the Object Pascal (.PAS) file you wish to add to the project.

If you are copying Object Pascal source files from a Delphi project directory over to a C++Builder project directory, be sure you copy the form definition (.DFM) files and Windows resource (.RES) files associated with those source files to the C++Builder project directory as well.

When the C++Builder project containing the Delphi unit(s) is built, the Delphi units will automatically be compiled with the C++Builder version of the Delphi compiler. This compiler produces the following output:

•	A C++ header file with an .HPP extension containing the C++ equivalents of the Object Pascal declarations contained in the interface section of an Object Pascal source file.

•	A object code file (.OBJ) in a format compatible with C++Builder.

The C++ header files the compiler produces for the Delphi units can be included in any C++ source files that utilize the classes declared in the Delphi units.  Do not use header files generated with C++Builder 1.0 in C++Builder 3.0.


Using .pas files in C++Builder projects

When using .PAS files in C++Builder be aware that the following language concepts, structures, types, and options are not supported when generating OBJ and HPP files. Using them generates the corresponding errors and warnings:

Issue	Error

Real48	fatal error

Comp	warning only (semi-supported through a C++ class)

old-style Object types	fatal error

dispinterface	warning (supported as an interface)

$Z2 option	fatal error

initialized set > 4 bytes	fatal error

safecall calling convention (class methods only)	fatal error

dynamic calling convention (class methods only)	fatal error

dll import by index	fatal error

When adding a .PAS file to your project, you can not edit or modify the file.

For more information about interoperability issues between Delphi and C++Builder, see C++ Language support for the VCL.


Sharing packages

These topics concern the use of packages:

Packages in DLLs

Using Delphi packages

For more information about using packages, see About Packages.


Using Delphi packages

If you have components or other code in a Delphi 4 package, you can reuse it in C++Builder 4. However, you cannot use that package directly. You must either:

•	Recompile the source code using the command-line compiler.

•	Add the .pas files for these packages to to your C++Builder project.

In addition, if you are placing a Pascal component into a C++ package and are dropping that component into a C++ program, and the Use Package is checked, then you need to include the $ObjExportAll directive {$ObjExportAll On} in the pascal code for that component.  If you do not have this directive on, the component that is placed into the package, used by the EXE, will not work.

For more information see Using .pas files in C++Builder projects


Linking issues

Linking options with the C and Pascal runtime libraries

Packages in DLLs

DLLs and threading

Linking package issues


Linking options with the C and Pascal runtime libraries

There are 6 versions of the C RTL.

cw32	RTL static library

cw32i	Import library for RTL cw3240.dll

cw32mt	RTL multithreaded static library

cw32mti	Import library for multithreaded RTL cw3240mt.dll

cp32mt	VCL-compliant RTL multithreaded static library

cp32mti	VCL-compliant import library for multithreaded RTL cp3240mt.dll

For a complete list of the static and dynamic libraries shipped with C++Builder, see Static run-time libraries and Dynamic-link libraries. For more information about which runtime libraries the new IDEtoBPR uses when it converts old projects, see Converting IDE project files to BPR project files.

If you link your EXE to the dynamic version of the VCL-compliant C RTL, you will need to ship BORLNDMM.DLL with your application.

Memory management issues when combining statically and dynamically linked RTLs

When you call (the keywoord) delete, the memory is freed in the module in which the class was defined. This is because delete calls the destructor, which is defined in the module in which the class is defined.  If the destructor does not throw an exception, then it calls the default operator delete.

The module in which the memory is allocated, when an object is created with new, is an implementation detail subject to change, and therefore undocumented. For this reason, unless you are using abstract base classes or COM components, your modules that share objects should be linked the same way to the runtime library.


Packages in DLLs

See also

When you create DLLs with C++Builder, building them with packages reduces the footprint of the entire application.  The executable, the DLL, and the package share one copy of the packaged code.  If you build a DLL with packages and call the DLL in the application, the application should be built with the same package as the DLL.

The following topics address specific areas to be aware of when using packages in DLLs.

The Application object

Modifications to global variables and events

Startup and shutdown issues with DLLs


The Application object

When using packages all globals are shared between all modules in the process.  The global Application object, for example,  available to the package-built DLL, is the same object instance used by the host EXE, and all other packages.  This is also true for the global clipboard, printer, standard I/O file handles, and any other global data. These global variables (but not thread variables) in packaged units are accessible anywhere in the application because there is only one copy of the packaged code that is shared among all modules. This includes other packages and the host EXE itself, thus creating a single namespace for global data.  If your application uses VCL40, each package, as well as the host EXE, share an instance of the VCL runtime code.


Modififcations to global variables and events
Modifications to global variables and events

When you access the VCL Application variable in a package, you are accessing the same TAPplication or TWebApplication instance used by the host EXE. And if a DLL built with VCL40 modifies the Application object, it too is accessing the same Application used by the host EXE.

DLLs built with packages should not modify the application event properties.  The application object should be considered the property of the host EXE.  Installable modules should negotiate with the host EXE to receive notification of application events, rather than modify the event properties directly.  This is also true for data properties.  You do not want a runtime loaded DLL to change the Application.HelpFile of the entire application.

Chaining event properties (saving the exiting property value, installing your own method, and calling the original from within your method) is not advisable.  You can not remove a module from the event chain without affecting everything that hooked in after that module did.  This is a particalary bad idea when you are dynamically loading modules at runtime. It is similar to "interrupt chaining" when working with DOS TSRs.


Startup and shutdown issues with DLLs

There are always startup/shutdown issues when dealing with DLLs, because unit initialization blocks inside the DLL are called when the DLL is loaded, and finalizations are called when the DLL is unloaded.  Because Windows does not guarantee the order in which implicitly loaded DLLs are unloaded, it is possible for the DLL finalization code to refer to code that has already been unloaded.  This usually results in crash-on-exit or crash-on-dll-unload behavior.

One solution to this is to not use DLLs built with packages, but to build the DLLs themselves as packages.  The host EXE then calls Sysutils::LoadPackage to load the module instead of LoadLibrary, and Sysutils::UnloadPackage instead of FreeLibrary.  This can solve crash-on-exit problems caused by order-of-dll-unloading because UnloadPackage calls the finalization blocks in the target package before asking Windows to unload the module.

There is a situation which could cause crash-on-exit / crash-on-dll-unload problems.  This applies if you are writing code that calls CoInitialize in the startup section, and CoUninitialize in the shutdown section.  Though Microsoft documentation states that CoInitialize/CoUninitialize must always be called before using OLE code, the reality is that these routines must never be called in DLL startup or shutdown code.  CoUninitialize can cause crashes or system deadlocks if called in DLL shutdown code (a unit finalization block).

For more information, see Startup and shutdown issues with packages.


DLLs and threading

Another area to be aware of is threading.  If a C++Builder DLL module is loaded into a multithreaded host EXE (C++Builder, Delphi or otherwise), the DLL must set its IsMultiThreaded global variable to true to enable the thread protection mechanisms inside the heap manager.  There is no other way for the DLL heap manager to find out that it is going to be used in a multi-threaded manner.  Similarly, C++Builder code that spawns new threads should always do so using System::BeginThread rather than the low-level Win32 API CreateThread.


Linking package issues

Be aware that you cannot import via a DEF file for a package.  The syntax for IMPORTS section of DEF files does not allow for the package module name's extension. It is assumed they have .DLL extension.  In the following example:

IMPORTS

[InternalName=]ModuleName.Entry

you cannot specifiy ModuleName to have a BPL extension.  To use a package, must use its import library, and prototype its functions in the code where they are being called from with __declspec(package) modifier.  For more information about the package argument, see the __declspec keyword extension.

The linking behavior of "packages" differs from that of DLLs.  The following advanced topics provide detailed information of this subject. This information is not required for customers using packages.

DLL review

Initialization order of OBJs

Initialization order of units

Packages (.BPLs) vs. .DLLs

Stating unit dependencies

Weak units

Reference counting

Startup and shutdown issues with packages


DLL review

A .DLL is a collection of .OBJ files, or modules, that an .EXE can link to either "statically" -- meaning that the .DLL must be present for the .EXE to run -- or "dynamically", which means that the .DLL loads only when the .EXE needs it to.

There is a difference between statically linking a .DLL, and "using static linking".

•	Static linking means that you are linking with a library that contains all of the necessary OBJs. This is not a DLL, but rather a static library.  Typically these have a .LIB extension.

•	Statically linking with a .DLL means that you are linking with an import library which contains references to the DLL.

•	Dynamically loading the .DLL means that you are calling the WinAPI function "LoadLibrary".

So the three permutations are: static linking with a .LIB, statically linking with an import library (also a LIB) which references a .DLL, and dynamically loading a .DLL (using "LoadLibrary").


Initialization order of OBJs

When a .DLL is statically linked, it is initialized by the startup code for the .EXE.  This means it will get initialized before "main" or "WinMain" is run.  When a .DLL is dynamically loaded, it will be initialized at the time it is loaded.

The meaning of "to be initialized" is the following: any #pragma startup directives, or declarations of global C++ objects, that occur within the .CPP files that make up the .OBJs that make up the .DLL, will cause entries to be recorded in each .OBJ file's _INIT_ segment. These "init entries" each have a priority value, and a reference to a function.  At the time the .DLL is created, all of the init entries are collected into a table in the .DLL's DATA segment called the "init table".  This init table is a ordered listing of all the init entries that were found throughout the entire set of .OBJs that comprise the DLL.  The ordering of these init entries depends: first, on their priority value; and second, on how the .OBJ files were ordered on the link line.

For example, if the link line contains A.OBJ, B.OBJ and C.OBJ, each with three global objects (whose constructors will get entered into the _INIT_ segments for each, all with the same priority value of 0x20), then the order in which the inits will be called, since the priority values are all the same, will depend on the ordering of the OBJs in the link line.  Changing the link order of the .OBJs will change the order in which the global object constructors get called.

Now, when an .EXE is statically linked to a .DLL, the startup code in the .EXE (c0x32.obj) calls "LoadLibrary" on the .DLL.  This call to "LoadLibrary" causes the startup code in .DLL (c0d32.obj), to successively call each of the init entries in the .DLL's init table.


Initialization order of units

The concept of a "unit" in C++ is new.  In the past, there was no distinction between a regular .OBJ generated by BCC32, and a unit OBJ (which can be generated by BCC32 using the #pragma directive "package(smart_init)"; all DCC32 generated .OBJs are considered units).

A unit differs from a regular .OBJ in the way it initializes.  A unit can have startup code and global objects just like a regular .OBJ. The difference is that, if a unit depends on another unit, that other unit must be initialized before the first unit.  This is achieved by special logic within ILink32 which maintains a dependency map between modules, to ensure that any referenced .OBJs are initialized first.

This also means that order in which init entries are processed is different.  For units, it is: first, in the reverse order in which the units are used; second, in link order, in the case where some units are initialized that are not directly referred to by other units; and third, in priority order within the unit.

Imagine again that A.OBJ, B.OBJ and C.OBJ contain init functions.  But this time they are all units, and instead of declaring the inits by way of global constructors, the user uses #pragma startup, with priority values of 10, 20 and 30.  The function are named according to their priority value and parent .OBJ, so that names are a10, a20, a30, b10, etc.

Also consider that A uses B and C, all three are units, and the link order is the same (A, B then C).  The ultimate order of initialization will be:

    b10 b20 b30 c10 c20 c30 a10 a20 a30

If these .OBJs had not been units, the order would have been:

    a10 b10 c10 a20 b20 c30 a30 b30 c30

The semantics of initialization are very different between units and regular .OBJs.

At this point in time, "smart initialization" is the only difference between units and regular .OBJs, hence the name of the #pragma directive, "package(smart_init)".  The reasoning behind the word "package" is because units are usually included within packages, although this is by no means a requirement.


Initialization order of units
Packages (.BPLs) vs. .DLLs

There is not much difference between a .DLL and a package if they are both dynamically loaded.  Here are the syntactic and semantic differences:

.DLL

•	Loaded with "LoadLibrary".

•	All inits are processed in:

1) priority order

2) link order.

•	Functions and data are exported using "__export".

•	The user import's data using "__declspec(dllimport)", or "__import".

.BPL (package)

•	Loaded with "LoadPackage".

•	All inits are processed in:

1) reverse of unit dependency order

2) link order

3) priority order.

•	Functions and data are exported using "__declspec(package)".

•	The user import's data using "__declspec(package)".

The major difference appears when you statically link with the BPL's import library, which has the extension .BPI (for "Borland Package Import Library").

•	First, init entries are not copied into an init table as with a .DLL.  Rather, they are copied into a special "__PackageInfoTable", which LoadPackage() knows how to read.

•	Second, the startup code used is c0pkg32.obj, instead of c0d32.obj. c0pkg32.obj does not call any unit inits (because it does not process the __PackageInfoTable).  It does, however, process inits for any regular .OBJs that occur within the package.  The init entries for these regular .OBJs are copied into the same place as for a regular DLL, and in all other respects will preserve the same semantics as a regular .DLL.  To state it another way, a .BPL composed entirely of non-units will behave just like a regular .DLL.  The only remaining difference is that some additional resources are written to the end of a .BPL (that helps Presto manage things that I myself don't quite understand.)

So, the regular .OBJ inits are copied into a plain init table, which c0pkg32 inits on startup of the package.  unit inits are copied into a __PackageInfoTable, which "LoadPackage" inits when it gets called. However, in the case when you are statically linking using the .BPI, LoadPackage is not called.  Unit inits are called by ILink32 copying the unit init entries *for the units within the .BPL that are actually used* into the init table for the .EXE itself.  Then, when the .EXE starts up, it will load the .BPL into memory, and initialize only those units within the .BPL that are needed.

To review: a .BPL that is dynamically loaded will have all of its units initialized, by LoadPackage, in the order mentioned above.  A BPL that is statically linked (using the .BPI), will have only those units that are actually used initialized, by the startup code for the EXE itself, also in the order mentioned above (although it will be only a subset of the dynamically loaded case).

This "partial initialization" behavior can have several speed advantages, especially since VCL40.BPI is already large, and not everyone needs to use all of the units the reside within it (Activex, Richedit, Commdlg, etc).  Note, however, that partial initialization will only occur where units are used; regular .OBJs are still initialized as with a .DLL, so no partiality is allowed.

A package is a basically a .DLL, primarily containing units, that permits partial initialization when it is statically linked to an EXE.  It also happens to contain special resources that allow the IDE to add it to the component palette, etc., if it happens to be a package implementation a component.


Stating unit dependencies

In Object Pascal, unit dependencies are made explicit with the "uses" directive.  But C++ has no such directive.  In C++, ILink32 resolves this problem by generating a module dependency map whenever a unit fails to explicitly mention another unit whose symbols it happens to use.  It can do this because we know which symbols every unit requires in order to link.  These "external references" indicate which other units that unit needs.

There does, however, exist a way to make unit dependencies explicit, using the #pragma link directive.  (Note: it is possible that this may change to #pragma uses in the future, since #pragma link is also used to force inclusion of other .OBJ files in a link; the two concepts are slightly different).

If an .OBJ is not a unit, but a regular .OBJ, no dependency map is kept, because there is no need to initialize its referenced .OBJs first. This differs from previous approaches.


Weak units

If an .OBJ (either a unit, or a regular .OBJ) is marked "#pragma package(smart_inti, weak)", it means that it will never be included within a .DLL or a .BPL.  Rather, the entire content of the .OBJ will be copied over to the import library.  To the user, weak .OBJs are invisible.  But this is how they work:

Consider a "myserv.OBJ" that imports data from a 23 MB database .DLL.  That .OBJ itself, however, is only 20 K large. Also, it takes over a minute for the database .DLL to initialize.

You are a tools vendor, producing a .DLL called "my.dll", which contains various routines.

One of the modules in this library is "myserv.obj".

However, only 1% of your customers really need myserv.obj's services.  The other 99% are really annoyed by the fact that they have to load up a 23 MB .DLL, all because of a module that they do not even use.

Previously, this was solved by splitting my.dll into multiple .DLLs.

By marking MYSERV as a weak .OBJ, it will never be included within the .DLL.  Rather, it will get copied, verbatim, into the import library for realcool.dll.  This means that people who do not use it will not get it -- and will not be forced to load the database .DLL -- and people who do use it will get it -- including the .DLL reference.

From the user's point of view there is just one .DLL, and one import library.

The partial initialization for packages does not do exactly the same thing.  References to external .DLLs are maintained in the header section of the referencing .BPL itself.  There is no way to say, "only bring in this other .DLL if the unit is actually used".  All referenced .DLLs are loaded by the operating system regardless of how much actual code you use.  Hence the need for something like a weak OBJ.

Weak .OBJs do not have to be units.  This is a generic service that is orthogonal to whether units or packages are being used.


Reference counting

If two .EXEs statically link to the same .BPL, the .BPL should only be initialized once.  This is done by reference counting code generated by ILink32 within the init and exit code of the units comprising the BPL.


Startup and shutdown issues with packages

The System unit in the VCL40.BPL package is special. It will always be initialized before anything else (even the RTL itself), and will be finalized last.  This is because it brings up and shuts down the memory manager, after which point no one else can reference dynamically allocated memory.

Everything that has been said about "initialization" applies in direct reverse to "finalization", a parallel concept which was not mentioned. Whereas #pragma startup and global object constructors cause init entries to be created, #pragma exit and global object destructors cause exit entries to be created.


Preprocessor Directives

Preprocessor directives are usually placed at the beginning of your source code, but they can legally appear at any point in a program. The C++Builder preprocessor detects preprocessor directives (also known as control lines) and parses the tokens embedded in them. C++Builder supports these preprocessor directives:

# (null directive)	#ifdef

#define	#ifndef

#elif	#include

#else	#line

#endif	#pragma

#error	#undef

#if

Any line with a leading # is taken as a preprocessing directive, unless the # is within a string literal, in a character constant, or embedded in a comment. The initial # can be preceded or followed by whitespace (excluding new lines).


# (null directive)

Directives

Syntax

#

Description

The null directive consists of a line containing the single character #. This line is always ignored.


#define

See also	Example	Directives

Syntax

#define macro_identifier <token_sequence>

Description

The #define directive defines a macro. Macros provide a mechanism for token replacement with or without a set of formal, function-like parameters.

Each occurrence of macro_identifier in your source code following this control line will be replaced in the original position with the possibly empty token_sequence (there are some exceptions, which are noted later). Such replacements are known as macro expansions. The token sequence is sometimes called the body of the macro.

An empty token sequence results in the removal of each affected macro identifier from the source code.

After each individual macro expansion, a further scan is made of the newly expanded text. This allows for the possibility of nested macros: The expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands into what looks like a preprocessing directive, such a directive will not be recognized by the preprocessor. There are these restrictions to macro expansion:

Any occurrences of the macro identifier found within literal strings, character constants, or comments in the source code are not expanded.

A macro won't be expanded during its own expansion (so #define A A won't expand indefinitely).

Example

#define HI "Have a nice day!"

#define empty

#define NIL ""

#define GETSTD #include <stdio.h>


#undef

See also	Example	Directives

Syntax

#undef macro_identifier

Description

You can undefine a macro using the #undef directive. #undef detaches any previous token sequence from the macro identifier; the macro definition has been forgotten, and the macro identifier is undefined. No macro expansion occurs within #undef lines.

The state of being defined or undefined turns out to be an important property of an identifier, regardless of the actual definition. The #ifdef and #ifndef conditional directives, used to test whether any identifier is currently defined or not, offer a flexible mechanism for controlling many aspects of a compilation.

After a macro identifier has been undefined, it can be redefined with #define, using the same or a different token sequence.

Attempting to redefine an already defined macro identifier will result in a warning unless the new definition is exactly the same token-by-token definition as the existing one. The preferred strategy where definitions might exist in other header files is as follows:

#ifndef BLOCK_SIZE

  #define BLOCK_SIZE 512

#endif

The middle line is bypassed if BLOCK_SIZE is currently defined; if BLOCK_SIZE is not currently defined, the middle line is invoked to define it.

No semicolon (;) is needed to terminate a preprocessor directive. Any character found in the token sequence, including semicolons, will appear in the macro expansion. The token sequence terminates at the first non-backslashed new line encountered. Any sequence of whitespace, including comments in the token sequence, is replaced with a single-space character.


Example

#define BLOCK_SIZE 512

  .

  .

  .

#undef BLOCK_SIZE

/* use of BLOCK_SIZE now would be illegal "unknown" identifier */

  .

  .

  .

#define BLOCK_SIZE 128   /* redefinition */


Using the -D and -U command-line options

See also

Identifiers can be defined and undefined using the command-line compiler options -D and -U.

The command line

BCC32 -Ddebug=1; paradox=0; X -Umysym myprog.c

is equivalent to placing

#define debug 1

#define paradox 0

#define X

#undef mysym

in the program.


Keywords and Protected Words in Macros
Keywords and Protected Words as Macros

It is legal but ill-advised to use C++Builder keywords as macro identifiers:

#define int long    /* legal but probably catastrophic */

#define INT long    /* legal and possibly useful */

The following predefined global identifiers cannot appear immediately following a #define or #undef directive:

_ _DATE_ _	_ _FILE_ _	_ _LINE_ _

_ _STDC_ _	_ _TIME_ _


Macros with Parameters

See also

The following syntax is used to define a macro with parameters:

#define macro_identifier(<arg_list>) token_sequence

Any comma within parentheses in an argument list is treated as part of the argument, not as an argument delimiter.

Note there can be no whitespace between the macro identifier and the (. The optional arg_list is a sequence of identifiers separated by commas, not unlike the argument list of a C function. Each comma-delimited identifier plays the role of a formal argument or placeholder.

Such macros are called by writing

macro_identifier<whitespace>(<actual_arg_list>)

in the subsequent source code. The syntax is identical to that of a function call; indeed, many standard library C "functions" are implemented as macros. However, there are some important semantic differences, side effects, and potential pitfalls.

The optional actual_arg_list must contain the same number of comma-delimited token sequences, known as actual arguments, as found in the formal arg_list of the #define line: There must be an actual argument for each formal argument. An error will be reported if the number of arguments in the two lists is different.

A macro call results in two sets of replacements. First, the macro identifier and the parenthesis-enclosed arguments are replaced by the token sequence. Next, any formal arguments occurring in the token sequence are replaced by the corresponding real arguments appearing in the actual_arg_list.

As with simple macro definitions, rescanning occurs to detect any embedded macro identifiers eligible for expansion.


Nesting Parentheses and Commas

The actual_arg_list can contain nested parentheses provided that they are balanced; also, commas appearing within quotes or parentheses are not treated like argument delimiters.

#define ERRMSG(x, str) showerr("Error:, x. str)

#define SUM(x,y)  ((x) + (y))

.

.

.

ERRMSG(2, "Press Enter, then Esc");

/* expands to:  showerr("Error",2,"Press Enter, then Esc");

return SUM(f(i, j), g(k,l));

/* expands to: return ((f(i,j) + (g(k,l))); */


Token Pasting with ##

You can paste (or merge) two tokens together by separating them with ## (plus optional whitespace on either side). The preprocessor removes the whitespace and the ##, combining the separate tokens into one new token. You can use this to construct identifiers.

Given the definition

#define VAR(i, j) (i##j)

 the call VAR(x, 6) expands to (x6). This replaces the older nonportable method of using (i/**/j).


Converting to Strings with #

The # symbol can be placed in front of a formal macro argument in order to convert the actual argument to a string after replacement.

Given the following definition:

#define TRACE(flag) printf(#flag "=%d\n", flag)

the code fragment

int highval = 1024;

TRACE(highval);

becomes

int highval = 1024;

printf("highval" "=%d\n", highval);

which, in turn, is treated as

int highval = 1024;

printf("highval=%d\n", highval);


Using the Backslash (\) for Line Continuation

A long token sequence can straddle a line by using a backslash (\). The backslash and the following newline are both stripped to provide the actual token sequence used in expansions.

#define WARN "This is really a single-\

line warning."

.

.

.

puts(WARN)

/* Screen will show: This is really a single-line warning. */


Side Effects and Other Dangers

The similarities between function and macro calls often obscure their differences. A macro call has no built-in type checking, so a mismatch between formal and actual argument data types can produce bizarre, hard-to-debug results with no immediate warning. Macro calls can also give rise to unwanted side effects, especially when an actual argument is evaluated more than once.

Compare CUBE and cube in the following example.

int cube(int x) {

   return x* x*x;

   }

#define CUBE(x)  ( (x)* (x) * (x) )

...

int b = 0, a = 3;

b = cube(a++);

/* cube() is passed actual arg = 3; so b = 27; a now = 4 */

a = 3;

b = CUBE(a++);

/* expands as ((a++)*(a++)*(a++)); a now = 6 */


#include

Example	Directives

Syntax

#include <header_name>

#include "header_name"

#include macro_identifier

Description

The #include directive pulls in other named files, known as include files, header files, or headers, into the source code. The syntax has three versions:

The first and second versions imply that no macro expansion will be attempted; in other words, header_name is never scanned for macro identifiers. header_name must be a valid file name with an extension (traditionally .h for header) and optional path name and path delimiters.

The third version assumes that neither < nor " appears as the first non-whitespace character following #include; further, it assumes a macro definition exists that will expand the macro identifier into a valid delimited header name with either of the <header_name> or "header_name" formats.

The preprocessor removes the #include line and conceptually replaces it with the entire text of the header file at that point in the source code. The source code itself is not changed, but the compiler "sees" the enlarged text. The placement of the #include can therefore influence the scope and duration of any identifiers in the included file.

If you place an explicit path in the header_name, only that directory will be searched.

The difference between the <header_name> and "header_name" formats lies in the searching algorithm employed in trying to locate the include file.


Header File Search with <header_name>

The <header_name> version specifies a standard include file; the search is made successively in each of the include directories in the order they are defined. If the file is not located in any of the default directories, an error message is issued.


Header File Search with "header_name"

The "header_name" version specifies a user-supplied include file; the file is searched in the following order:

 - in the same directory of the file that contains the #include statement

 - in the directories of files that include (#include) that file

 - the current directory

 - along the path specified by the /I compiler option


Example

This #include statement causes it to look for stdio.h in the standard include directory.

#include <stdio.h>

This #include statement causes it to look for MYINCLUD.H in the current directory, then in the default directories.

#include "myinclud.h"

After expansion, this #include statement causes the preprocessor to look in C:\BCB\INCLUDE\MYSTUFF.H and nowhere else.

#define myinclud "C:\BCB\INCLUDE\MYSTUFF.H"

/* Note: Single backslashes OK here; within a C statement you would

   need "C:\\BCB\\INCLUDE\\MYSTUFF.H" */

#include  myinclud

/* macro expansion */


Conditional compilation

C++Builder supports conditional compilation by replacing the appropriate source-code lines with a blank line. The lines thus ignored are those beginning with # (except the #if, #ifdef, #ifndef, #else, #elif, and #endif directives), as well as any lines that are not to be compiled as a result of the directives. All conditional compilation directives must be completed in the source or include file in which they are begun.


defined

See also	Keywords

Syntax

#if defined[(] <identifier> [)]

#elif defined[(] <identifier> [)]

Description

Use the defined operator to test if an identifier was previously defined using #define. The defined operator is only valid in #if and #elif expressions.

Defined evaluates to 1 (true) if a previously defined symbol has not been undefined (using #undef); otherwise, it evaluates to 0 (false).

Defined performs the same function as #ifdef.

#if defined(mysym)

is the same as

#ifdef mysym

The advantage is that you can use defined repeatedly in a complex expression following the #if directive; for example,

#if defined(mysym) && !defined(yoursym)


#if, #elif, #else, and #endif

See also	Directives

Syntax

#if constant-expression-1

<section-1>

<#elif constant-expression-2 newline section-2>

  .

  .

  .

<#elif constant-expression-n newline section-n>

<#else <newline> final-section>

#endif

Description

C++Builder supports conditional compilation by replacing the appropriate source-code lines with a blank line. The lines thus ignored are those lines that are not to be compiled as a result of the directives. All conditional compilation directives must be completed in the source or include file in which they are begun.

The conditional directives #if, #elif, #else, and #endif work like the normal C conditional operators. If the constant-expression-1 (subject to macro expansion) evaluates to nonzero (true), the lines of code (possibly empty) represented by section-1, whether preprocessor command lines or normal source lines, are preprocessed and, as appropriate, passed to the C++Builder compiler. Otherwise, if constant-expression-1 evaluates to zero (false), section-1 is ignored (no macro expansion and no compilation).

In the true case, after section-1 has been preprocessed, control passes to the matching #endif (which ends this conditional sequence) and continues with next-section. In the false case, control passes to the next #elif line (if any) where constant-expression-2 is evaluated. If true, section-2 is processed, after which control moves on to the matching #endif. Otherwise, if constant-expression-2 is false, control passes to the next #elif, and so on, until either #else or #endif is reached. The optional #else is used as an alternative condition for which all previous tests have proved false. The #endif ends the conditional sequence.

The processed section can contain further conditional clauses, nested to any depth; each #if must be matched with a closing #endif.

The net result of the preceding scenario is that only one section (possibly empty) is passed on for further processing. The bypassed sections are relevant only for keeping track of any nested conditionals, so that each #if can be matched with its correct #endif.

The constant expressions to be tested must evaluate to a constant integral value.


#ifdef and #ifndef

See also	Directives

Syntax

#ifdef identifier

#ifndef identifier

Description

The #ifdef and #ifndef conditional directives let you test whether an identifier is currently defined or not; that is, whether a previous #define command has been processed for that identifier and is still in force. The line

#ifdef identifier

has exactly the same effect as

#if 1

if identifier is currently defined, and the same effect as

#if 0

if identifier is currently undefined.

#ifndef tests true for the "not-defined" condition, so the line

#ifndef identifier

has exactly the same effect as

#if 0

if identifier is currently defined, and the same effect as

#if 1

if identifier is currently undefined.

The syntax thereafter follows that of the #if, #elif, #else, and #endif.

An identifier defined as NULL is considered to be defined.


#line

Directives

Syntax

#line integer_constant  <"filename">

Description

You can use the #line directive to supply line numbers to a program for cross-reference and error reporting. If your program consists of sections derived from some other program file, it is often useful to mark such sections with the line numbers of the original source rather than the normal sequential line numbers derived from the composite program.

The #line directive indicates that the following source line originally came from line number integer_constant of filename. Once the filename has been registered, subsequent #line commands relating to that file can omit the explicit filename argument.

Macros are expanded in #line arguments as they are in the #include directive.

The #line directive is primarily used by utilities that produce C code as output, and not in human-written code.


#error

Example	Directives

Syntax

#error errmsg

Description

The #error directive generates the message:

Error: filename line# : Error directive: errmsg

This directive is usually embedded in a preprocessor conditional statement that catches some undesired compile-time condition. In the normal case, that condition will be false. If the condition is true, you want the compiler to print an error message and stop the compile. You do this by putting an #error directive within a conditional statement that is true for the undesired case.


Example

#if (MYVAL != 0 && MYVAL != 1)

#error MYVAL must be defined to either 0 or 1

#endif


#pragma summary

Directives

Syntax

#pragma directive-name

Description

With #pragma, C++Builder can define the directives it wants without interfering with other compilers that support #pragma. If the compiler doesn't recognize directive-name, it ignores the #pragma directive without any error or warning message.

C++Builder supports the following #pragma directives:

#pragma alignment

#pragma anon_struct

#pragma argsused

#pragma checkoption

#pragma codeseg

#pragma comment

#pragma exit

#pragma hdrfile

#pragma hdrstop

#pragma inline

#pragma intrinsic

#pragma link

#pragma message

#pragma nopushoptwarn

#pragma obsolete

#pragma option

#pragma pack

#pragma package

#pragma resource

#pragma startup

#pragma warn


#pragma alignment

See also	#pragma

Syntax

#pragma alignment

Description

The alignment directive emits a message specifying the current alignment and enum size. For example:

W8035: The alignment is 8 bytes, the enum size is 4 bytes

The message will only be displayed in the IDE if the Compiler options for “Show general messages” is checked. The message can also be enabled or disabled using the compiler's -wmsg switch.


#pragma anon_struct

See also	#pragma

Syntax

#pragma anon_struct on

#pragma anon_struct off

Description

The anon_struct directive allows you to compile anonymous structures embedded in classes.

#pragma anon_struct on

struct S {

   int i;

   struct {  // Embedded anonymous struct

      int   j ;

      float x ;

   };

   class {  // Embedded anonymous class

   public:

      long double ld;

   };

S() { i = 1; j = 2; x = 3.3; ld = 12345.5;}

};

#pragma anon_struct off

void main() {

   S mystruct;

   mystruct.x = 1.2;  // Assign to embedded data.

   }


#pragma argsused

See also	#pragma

Syntax

#pragma argsused

Description

The argsused pragma is allowed only between function definitions, and it affects only the next function. It disables the warning message:

"Parameter name is never used in function func-name"


#pragma checkoption

See also	#pragma

Syntax

#pragma checkoption optionstring

Description

The checkoption pragma checks that the options in 'optionstring' are actually set. If they are not, an ERROR is emitted:

E2471: pragma checkoption failed: options are not as expected

Use the checkoption pragma with an option string indicating the command-line options to check for.  For example:

#pragma checkoption -a4 -b

#pragma checkoption optionstring is similar to #pragma option optionstring, which attempts to set the options in 'optionstring'.


#pragma codeseg

See also	#pragma

Syntax

#pragma codeseg <seg_name> <"seg_class"> <group>

Description

The codeseg directive lets you name the segment, class, or group where functions are allocated. If the pragma is used without any of its options, the default code segment is used for function allocation.


#pragma comment

See also	#pragma

Syntax

#pragma comment (comment type, "string")

Description

The comment directive lets you write a comment record into an output file. The comment type can be one of the following values:

Value	Explanation

exestr	The linker writes string into an .OBJ file. Your specified string is placed in the executable file. Such a string is never loaded into memory but can be found in the executable file by use of a suitable file search utility.

lib	Writes a comment record into an .OBJ file. A library module that is not specified in the linker's response-file can be specified by the comment LIB directive. The linker includes the library module name specified in string as the last library. Multiple modules can be named and linked in the order in which they are named.

user	The compiler writes string into the .OBJ file. The specified string is ignored by the linker.


#pragma curious_george

See also	#pragma

Syntax

#pragma curious_george

Description

The #pragma curious_george directive prints out the ‘warning’: No eating puzzle pieces!

This message will only be displayed in the IDE if the Compiler options for “Show general messages” is checked. The message can also be enabled or disabled using the compiler's -wmsg switch.


#pragma exit and #pragma startup

See also	#pragma

Syntax

#pragma startup function-name <priority>

#pragma exit function-name <priority>

Description

These two pragmas allow the program to specify function(s) that should be called either upon program startup (before the main function is called), or program exit (just before the program terminates through _exit).

The specified function-name must be a previously declared function taking no arguments and returning void; in other words, it should be declared as:

void func(void);

The optional priority parameter should be an integer in the range 64 to 255. The highest priority is 0. Functions with higher priorities are called first at startup and last at exit. If you don't specify a priority, it defaults to 100.

Note:	Priorities from 0 to 63 are used by the C libraries, and should not be used by the user.


#pragma hdrfile

See also	#pragma

Syntax

#pragma hdrfile "filename.CSM"

Description

This directive sets the name of the file in which to store precompiled headers.

If you aren't using precompiled headers, this directive has no effect. You can use the command-line compiler option -H=filename or Use Precompiled Headers to change the name of the file used to store precompiled headers.


#pragma hdrstop

See also	#pragma

Syntax

#pragma hdrstop

Description

This directive terminates the list of header files eligible for precompilation. You can use it to reduce the amount of disk space used by precompiled headers.

Precompiled header files can be shared between the source files of your project only if the #include directives before #pragma hdrstop are identical. Therefore, you get the best compiler performance if you include common header files of your project before the #pragma hdrstop, and specific ones after it. Make sure the #include directives before the #pragma hdrstop are identical in all the source files, or that there are only very few variations.

The integrated development environment generates code to enhance precompiled header performance. For example, after a New Application, source file "Unit1.cpp" will look like this (comments added):

#include <vcl.h>       // common header file

#pragma hdrstop      // terminate list here

#include "Unit1.h"    // specific header file

// ....

Use this pragma directive only in source files. The pragma has no effect when it is used in a header file.


#pragma inline

See also	#pragma

Syntax

#pragma inline

Description

This directive is equivalent to the -B command-line compiler option.

This is best placed at the top of the file, because the compiler restarts itself with the -B option when it encounters #pragma inline.


#pragma intrinsic

See also	Example	#pragma

Syntax

#pragma intrinsic [-]function-name

Description

Use #pragma intrinsic to override command-line switches or IDE options to control the inlining of functions.

When inlining an intrinsic function, always include a prototype for that function before using it.


Example

This example causes the compiler to generate code for strcpy in your function:

#pragma intrinsic strcpy

 while this version prevents the compiler from inlining strcpy:

#pragma intrinsic -strcpy


#pragma link

See also	#pragma

Syntax

#pragma link “[path]modulename[.ext]”

Description

The directive instructs the linker to link the file into an executable file.

By default, the linker searches for modulename in the local directory and any path specified by the -L option. You can use the path argument to specify a directory.

By default, the linker assumes an .obj extension.


#pragma message

See also	Example	#pragma

Syntax

#pragma message ("text" ["text"["text" ...]])

#pragma message text

Description

Use #pragma message to specify a user-defined message within your program code.

The first form requires that the text consist of one or more string constants, and the message must be enclosed in parentheses. (This form is compatible with MSC.) The second form uses the text following the #pragma for the text of the warning message. With both forms of the #pragma, any macro references are expanded before the message is displayed. User-defined messages are displayed as messages, not warnings.

Display of user-defined messages is on by default and can be turned on or off with the Show Messages option. This option corresponds to the compiler's -wmsg switch.

Messages will only be displayed in the IDE if the Compiling tab on the Project|Options|Compiler page has the “Show general messages” box checked.


Example

The following example displays either "You are compiling using version xxx of C++Builder" (where xxx is the version number) or "Sorry, you are not using the C++Builder compiler".

#ifdef __BORLANDC__

#pragma message You are compiling using version __BORLANDC__ of C++Builder.

#else

#pragma message ("Sorry, you are not using the C++Builder compiler")

#endif


#pragma obsolete

See also	#pragma

Syntax

#pragma obsolete identifier

Description

Use #pragma obsolete to give a warning the first time the preprocessor encounters identifier in your program code after the pragma. The warning states that the identifier is obsolete.


#pragma option

See also	#pragma

Syntax

#pragma option options

#pragma option push options

#pragma option pop

#pragma nopushoptwarn

Description

Use #pragma option to include command-line options within your program code.  #pragma option can also be used with the push or pop arguments.

#pragma option [options...]

options can be any command-line option (except those listed in the following paragraph). Any number of options can appear in one directive. For example, both of the following are valid:

#pragma option -C

#pragma option -C -A

Any of the toggle options (such as -a or -K) can be turned on and off as on the command line. For these toggle options, you can also put a period following the option to return the option to its command-line, configuration file, or option-menu setting. This allows you to temporarily change an option, then return it to its default, without having to remember (or even needing to know) what the exact default setting was.

Options that cannot appear in a pragma option include:

-B	-c	-dname

-Dname=string	-efilename	-E

-Fx	-h	-lfilename

-lexset	-M	-o

-P	-Q	-S

-T	-Uname	-V

-X	-Y

You can use #pragmas, #includes, #define, and some #ifs in the following cases:

Before the use of any macro name that begins with two underscores (and is therefore a possible built-in macro) in an #if, #ifdef, #ifndef or #elif directive.

Before the occurrence of the first real token (the first C or C++ declaration).

Certain command-line options can appear only in a #pragma option command before these events. These options are:

-Efilename	-f	-i#

-m*	-npath	-ofilename

-u	-W	-z

*

Other options can be changed anywhere. The following options will only affect the compiler if they get changed between functions or object declarations:

-1	-h	-r

-2	-k	-rd

-a	-N	-v

-ff	-O	-y

-G	-p	-Z

The following options can be changed at any time and take effect immediately:

-A	-gn	-zE

-b	-jn	-zF

-C	-K	-zH

-d	-wxxx

The options can appear followed by a dot (.) to reset the option to its command-line state.

#pragma option using push or pop

The #pragma option directive can also be used with the push and pop arguments to enable you to easily modify compiler directives.

Using the #pragma option push allows you to save all (or a selected subset of) options before including any files that could potentially change many compiler options and warnings, and then, with the single statement, #pragma option pop, return to the previous state. For example:

#pragma option push

#include <theworld.h>

#pragma option pop

#include “mystuff.h”

The #pragma option push directive first pushes all compiler options and warning settings on a stack and then handles any options (if supplied). The following examples show how the #pragma option push can be used with or without options:

#pragma option push -C -A

#pragma option push

The #pragma option pop directive changes compiler options and warnings by popping the last set of options and warnings from the stack. It gives a warning, “Pragma option pop with no matching option push,” if the stack is empty, in which case nothing happens.

The following generates a warning about an empty stack:

#pragma option push

#pragma option pop

#pragma option pop      /* Warning */

We do not recommend it, but you can turn off this warning with the directive: #pragma warn -nop.

If you try to specify any options after pop, you get the error, ”Nothing allowed after pragma option pop.” For example, the following produces an error:

#pragma option pop -C	/* ERROR */

If your stack of pushed options is not the same at the start of a file as at the end of a file, you receive a warning: “Previous options and warnings not restored.” To turn off this warning, use the directive, #pragma nopushoptwarn.


#pragma pack

See also	#pragma

Syntax

#pragma pack([{push | pop}[,]] [identifier[,]] [n])

Description

The #pragma pack(n).directive is the same as using the #pragma option specifically with the -a compiler option. n is the byte alignment that determines how the compiler aligns data in stored memory. For more information see the -a compiler option. #pragma pack can also be used with push and pop arguments, which provide the same functionality as the #pragma option directive using push and pop. The following table compares the use of  #pragma pack with #pragma option.

#pragma pack	#pragma option

#pragma pack(n)	#pragma option -an

#pragma pack(push, n)	#pragma option push -an

#pragma pack(pop)	#pragma option pop

The #pragma pack directive also supports an identifier argument which must be used in combination with either push or pop.

#pragma pack with no arguments

#pragma pack()

Using #pragma pack with no arguments will set the packing size to the starting –aX alignment (which defaults to 4). The starting -aX alignment is considered the alignment at the start of the compile AFTER all commandline options have been processed.

#pragma pack using a value for n

#pragma pack(8)

Using #pragma pack with a value for 'n' will set the current alignment to 'n'. Valid alignments for ‘n’ are: 1,2,4,8, and 16.

#pragma pack using push

#pragma pack(push)

Using #pragma pack with push will push the current alignment on an internal stack of alignments.

#pragma pack using push, identifier

#pragma pack(push, ident)

Using #pragma pack with push and an identifier will associate the pushed alignment with 'identifier'.

#pragma pack using push and n

#pragma pack(push, 8)

#pragma pack(push, ident, 8)

Using #pragma pack with push with a value for 'n', will execute pragma pack push or pragma pack push identifier, and afterwards set the current alignment to 'n'.

#pragma pack using pop

#pragma pack(pop)

Using #pragma pack with pop will pop the alignment stack and set the alignment to the last alignment pushed. If the pop does not find a corresponding push, the entire stack of alignments is popped, and a warning is issued, and the alignment reverts to the starting -aX alignment..

#pragma pack using pop, identifier

#pragma pop(pop, ident)

Using #pragma pack with pop and an identifier will pop the stack until the identifier is found and set the alignment to the alignment pushed by the previous corresponding #pragma pack(push, identifier). If the pop with identifier does not find the corresponding push with an identifier, the entire stack of alignments is popped, and a warning is issued to the user:

W8083: Pragma pack pop with no matching pack push

The alignment will then be reset to the starting -aX alignment.

#pragma pack using pop and n

#pragma pack(pop, 8)

#pragma pack(pop, ident, 8)

Using #pragma pack with pop and a value for 'n', will execute pragma pack pop or pragma pack pop identifier. Afterwards the current alignment is set to 'n', unless pop fails to find a corresponding push, in which case 'n' is ignored, a warning is issued, and the alignment reverts to the starting -aX alignment.

Error conditions

Specifying an 'identifier' without push or pop is an error.

Specifying an alignment different from 1,2,4,8,16 is an error.

Warning conditions

Using #pragma pop without a corresponding push issues a warning.


#pragma package

See also	#pragma

Syntax

#pragma package(smart_init)

#pragma package(smart_init, weak)

Description: smart_init argument

The #pragma package(smart_init) assures that packaged units are initialized in the order determined by their dependencies. (Included by default in package source file.) Typically, you would use the #pragma package for .CPP files that are built as packages.

This pragma affects the order of initialization of that compilation unit. For units, initialization occurs in the following order:

1. By their "uses" dependencies, that is, if unitA depends on unitB, unitB must be initialized before unitA.

2. The link order.

3. Priority order within the unit.

For regular.OBJ files(those not built as units), initialization happens first according to priority order and then link order. Changing the link order of the .OBJ files changes the order in which the global object constructors get called.

The following examples show how the initialization differs between units and regular .OBJ files.

Take as an example three unit files, A, B and C that are “smart initialized” with #pragma package(smart_init) and have priority values (defined by the priority parameter of the #pragma startup) set of 10, 20 and 30. The functions are named according to their priority value and the parent .OBJ, so the names are a10, a20, a30, b10, and so on.

Since all three are units, and if A uses B and C and the link order is A, B then C, the order of initialization is:

B10 B20 B30 C10 C20 C30 A10 A20 A30

If the above were .OBJ files, not units, the order would be:

A10 B10 C10 A20 B20 C20 A30 B30 C30

The .CPP files that use #pragma package(smart_init) also require that any #pragma link references to other .OBJ files from a .CPP file that declares #pragma package(smart_init), must be resolved by a unit. #pragma link references to non .OBJ files can still be resolved by libraries, etc.

Description: weak packages

The #pragma package(smart_init, weak) directive affects the way an .OBJ file is stored in a package’s .BPI and .BPL files. If #pragma package(smart_init, weak) appears in a unit file, the compiler omits the unit from BPLs when possible, and creates a non-packaged local copy of the unit when it is required by another application or package. A unit compiled with this directive is said to be “weakly packaged”.

#pragma package(smart_init, weak) is used to eliminate conflicts among packages that may depend on the same external library.

Unit files containing the #pragma package(smart_init, weak) directive must not have global variables.

For more information about using weak packages, see Weak packaging.


#pragma resource

See also	#pragma

Syntax

#pragma resource "*.dfm"

Description

This pragma causes the file to be marked as a form unit and requires matching .dfm and header files. All such files are managed by the IDE.

If your form requires any variables, they must be declared immediately after the pragma resource is used. The declarations must be of the form

   TFormName *Formname;


#pragma warn

See also	Example	#pragma

Syntax

#pragma warn [+|-|.]xxx

Description

The warn pragma lets you override specific -wxxx command-line options or check Display Warnings. xxx is the three-letter or four-digit message identifier used by the command-line option.


Example

If your source code contains the directives:

#pragma warn +amb

#pragma warn -8011

#pragma warn .nod

the amb warning will be turned on, the 8011 warning will be turned off, and the nod warning will be restored to the value it had when compilation of the file began. See the command-line options summary for a complete list of the three-letter and four-digit warning message identifiers.


Predefined macros

See also

C++Builder predefines certain global identifiers known as manifest constants. Most global indentifers begin and end with two underscores (__).

Note: For readability, underscores are often separated by a single blank space. In your source code, you should never insert whitespace between underscores.

Macro	Value 	Description

_ _BCOPT_ _	1	Defined in any compiler that has an optimizer.

_ _BCPLUSPLUS_ _	0x0540	Defined if you've selected C++ compilation; will increase in later releases.

_ _BORLANDC_ _	0x0540	Version number.

_ _CDECL_ _ 	1	Defined if Calling Convention is set to cdecl; otherwise undefined.

_CHAR_UNSIGNED	1	Defined by default indicating that the default char is unsigned char. Use the -K option to undefine this macro.

_ _CONSOLE_ _	 	When defined, the macro indicates that the program is a console application.

_CPPUNWIND	1	Enable stack unwinding.This is true by default; use -xd- to disable.

_ _cplusplus	1	Defined if in C++ mode; otherwise, undefined.

_ _DATE_ _	String literal	Date when processing began on the current file.

_ _DLL_ _	1	Defined whenever the -WD option is used; otherwise undefined.

_ _FILE_ _	String literal	Name of the current file being processed.

_ _FLAT_ _	1	Defined when compiling in 32-bit flat memory model.

_ _LINE_ _	Decimal constant	Number of the current source file line being processed.

_M_IX86	1	Always defined. The default  value is 300. You can change the value to 400 or 500 by using the /4 or /5 options.

 _ _MSDOS_ _	1	Integer constant.

_ _MT_ _	1	Defined only if the -WM option is used. It specifies that the multithread library is to be linked.

_ _PASCAL_ _ 	1	Defined if Calling Convention is set to Pascal; otherwise undefined.

_ _STDC_ _	1	Defined if you compile with the -A option; otherwise, undefined.

_ _TCPLUSPLUS_ _ 	0x0540	Version number.

_ _TEMPLATES_ _	1	Defined as 1 for C++ files (meaning that templates are supported); otherwise, it is undefined.

_ _TIME_ _	String literal	Time when processing began on the current file.

_ _TLS_ _	1	Thread Local Storage. Always true in C++Builder.

_ _TURBOC_ _ 	0x0540	Will increase in later releases.

_WCHAR_T	1	Defined only for C++ programs to indicate that wchar_t is an intrinsically defined data type.

_WCHAR_T_DEFINED	1	Defined only for C++ programs to indicate that wchar_t is an intrinsically defined data type.

_Windows	 	Defined for Windows-only code.

_ _WIN32_ _	1	Defined for console and GUI applications.

Note:	_ _DATE_ _, _ _FILE_ _, _ _LINE_ _, _ _STDC_ _, and _ _TIME_ _ cannot appear immediately following a #define or #undef directive.


ANSI Implementation-specific standards

Certain aspects of the ANSI C standard are not defined exactly by ANSI. Instead, each implementor of a C compiler is free to define these aspects individually. This chapter describes how Borland has chosen to define these implementation-specific standards. The section numbers refer to the February 1990 C ANSI/ISO Standard. Remember that there are differences between C and C++; this topic addresses C only.

2.1.1.3 How to identify a diagnostic.

When the compiler runs with the correct combination of options, any messages it issues beginning with the words Fatal, Error, or Warning are diagnostics in the sense that ANSI specifies. The options needed to ensure this interpretation are as follows:

Options needed for ANSI compliance
Option	Action

–A	Enable only ANSI keywords.

–C–	No nested comments allowed.

–i32	At most 32 significant characters in identifiers.

–p–	Use C calling conventions.

–w–	Turn off all warnings.

–wbei	Turn on warning about inappropriate initializers.

–wbig	Turn on warning about constants being too large.

–wcpt	Turn on warning about nonportable pointer comparisons.

–wdcl	Turn on warning about declarations without type or storage class.

–wdup	Turn on warning about duplicate nonidentical macro definitions.

–wext	Turn on warning about variables declared both as external and as static.

–wfdt	Turn on warning about function definitions using a typedef.

–wrpt	Turn on warning about nonportable pointer conversion.

–wstu	Turn on warning about undefined structures.

–wsus	Turn on warning about suspicious pointer conversion.

–wucp	Turn on warning about mixing pointers to signed and unsigned char.

–wvrt	Turn on warning about void functions returning a value.

Other options not specifically mentioned here can be set to whatever you want.

2.1.2.2.1  The semantics of the arguments to main.

When the program is run on DOS, argv[0] points to the program name.

The remaining argv strings point to each component of the DOS command-line arguments. Whitespace separating arguments is removed, and each sequence of contiguous non-whitespace characters is treated as a single argument. Quoted strings are handled correctly (that is, as one string containing spaces).

2.1.2.3  What constitutes an interactive device.

An interactive device is any device that looks like the console.

2.2.1  The collation sequence of the execution character set.

The collation sequence for the execution character set uses the value of the character in ASCII.

2.2.1  Members of the source and execution character sets.

The source and execution character sets are the extended ASCII set supported by the IBM PC. Any character other than Ctrl+Z can appear in string literals, character constants, or comments.

2.2.1.2  Multibyte characters.

Multibyte characters are supported in C++Builder.

2.2.2  The direction of printing.

Printing is from left-to-right, the normal direction for the PC.

2.2.4.2  The number of bits in a character in the execution character set.

There are 8 bits per character in the execution character set.

3.1.2  The number of significant initial characters in identifiers.

The first 32 characters are significant, although you can use a command-line option (–i) to change that number. Both internal and external identifiers use the same number of significant characters. (The number of significant characters in C++ identifiers is unlimited.)

3.1.2  Whether case distinctions are significant in external identifiers.

The compiler normally forces the linker to distinguish between uppercase and lowercase. You can use a command-line option (–lc–) to turn off case sensitivity.

3.1.2.5  The representations and sets of values of the various types of integers.

Identifying diagnostics in C++

Type	Minimum value	Maximum value
signed char	–128	127
unsigned char	0	255
signed short	–32,768	32,767
unsigned short	0	65,535
signed int	–2,147,483,648	–2,147,483,647
unsigned int	0	4,294,967,295
signed long	–2,147,483,648	2,147,483,647
unsigned long	0	4,294,967,295

All char types use one 8-bit byte for storage.

All short types use 2 bytes.

All int types use 4 bytes.

All long types use 4 bytes.

If alignment is requested (–a), all nonchar integer type objects will be aligned to even byte boundaries. If the requested alignment is –a4, the result is 4-byte alignment. Character types are never aligned.

3.1.2.5  The representations and sets of values of the various types of floating-point numbers.

The IEEE floating-point formats as used by the Intel 8086 are used for all C++Builder floating-point types. The float type uses 32-bit IEEE real format. The double type uses 64-bit IEEE real format. The long double type uses 80-bit IEEE extended real format.

3.1.3.4  The mapping between source and execution character sets.

Any characters in string literals or character constants remain unchanged in the executing program. The source and execution character sets are the same.

3.1.3.4  The value of an integer character constant that contains a character or escape sequence not represented in the basic execution character set or the extended character set for a wide character constant.

Wide characters are supported.

3.1.3.4  The current locale used to convert multibyte characters into corresponding wide characters for a wide character constant.

Wide character constants are recognized.

3.1.3.4  The value of an integer constant that contains more than one character, or a wide character constant that contains more than one multibyte character.

Character constants can contain one or two characters. If two characters are included, the first character occupies the low-order byte of the constant, and the second character occupies the high-order byte.

3.2.1.2  The result of converting an integer to a shorter signed integer, or the result of converting an unsigned integer to a signed integer of equal length, if the value cannot be represented.

These conversions are performed by simply truncating the high-order bits. Signed integers are stored as two’s complement values, so the resulting number is interpreted as such a value. If the high-order bit of the smaller integer is nonzero, the value is interpreted as a negative value; otherwise, it is positive.

3.2.1.3  The direction of truncation when an integral number is converted to a floating-point number that cannot exactly represent the original value.

The integer value is rounded to the nearest representable value. Thus, for example, the long value (231 –1) is converted to the float value 231. Ties are broken according to the rules of IEEE standard arithmetic.

3.2.1.4  The direction of truncation or rounding when a floating-point number is converted to a narrower floating-point number.

The value is rounded to the nearest representable value. Ties are broken according to the rules of IEEE standard arithmetic.

3.3  The results of bitwise operations on signed integers.

The bitwise operators apply to signed integers as if they were their corresponding unsigned types. The sign bit is treated as a normal data bit. The result is then interpreted as a normal two’s complement signed integer.

3.3.2.3  What happens when a member of a union object is accessed using a member of a different type.

The access is allowed and the different type member will access the bits stored there. You’ll need a detailed understanding of the bit encodings of floating-point values to understand how to access a floating-type member using a different member. If the member stored is shorter than the member used to access the value, the excess bits have the value they had before the short member was stored.

3.3.3.4  The type of integer required to hold the maximum size of an array.

For a normal array, the type is unsigned int, and for huge arrays the type is signed long.

3.3.4  The result of casting a pointer to an integer or vice versa.

When converting between integers and pointers of the same size, no bits are changed. When converting from a longer type to a shorter type, the high-order bits are truncated. When converting from a shorter integer type to a longer pointer type, the integer is first widened to an integer type the same size as the pointer type.

Thus signed integers will sign-extend to fill the new bytes. Similarly, smaller pointer types being converted to larger integer types will first be widened to a pointer type as wide as the integer type.

3.3.5  The sign of the remainder on integer division.

The sign of the remainder is negative when only one of the operands is negative. If neither or both operands are negative, the remainder is positive.

3.3.6  The type of integer required to hold the difference between two pointers to elements of the same array, ptrdiff_t.

The type is signed int.

3.3.7  The result of a right shift of a negative signed integral type.

A negative signed value is sign extended when right shifted.

3.5.1  The extent to which objects can actually be placed in registers by using the register storage-class specifier.

Objects declared with any one, two, or four-byte integer or pointer types can be placed in registers. At least two and as many as seven registers are available. The number of registers actually used depends on what registers are needed for temporary values in the function.

3.5.2.1  Whether a plain int bit-field is treated as a signed int or as an unsigned int bit field.

Plain int bit fields are treated as signed int bit fields.

3.5.2.1  The order of allocation of bit fields within an int.

Bit fields are allocated from the low-order bit position to the high-order.

3.5.2.1  The padding and alignment of members of structures.

By default, no padding is used in structures. If you use the word alignment option (–a), structures are padded to even size, and any members that do not have character or character array type are aligned to an even multiple offset.

3.5.2.1  Whether a bit-field can straddle a storage-unit boundary.

Depending upon the overall alignment and the type alignment, a bit field is allowed to straddle a storage unit.

3.5.2.2  The integer type chosen to represent the values of an enumeration type.

Store all enumerators as full ints. Store the enumerations in a long or unsigned long if the values don’t fit into an int. This is the default behavior as specified by –b compiler option.

The –b- behavior specifies that enumerations should be stored in the smallest integer type that can represent the values. This includes all integral types, for example, signed char, unsigned char, signed short, unsigned short, signed int, unsigned int, signed long, and unsigned long.

For C++ compliance, –b- must be specified because it is not correct to store all enumerations as ints for C++.

3.5.3  What constitutes an access to an object that has volatile-qualified type.

Any reference to a volatile object will access the object. Whether accessing adjacent memory locations will also access an object depends on how the memory is constructed in the hardware. For special device memory, such as video display memory, it depends on how the device is constructed. For normal PC memory, volatile objects are used only for memory that might be accessed by asynchronous interrupts, so accessing adjacent objects has no effect.

3.5.4  The maximum number of declarators that can modify an arithmetic, structure, or union type.

There is no specific limit on the number of declarators. The number of declarators allowed is fairly large, but when nested deeply within a set of blocks in a function, the number of declarators will be reduced. The number allowed at file level is at least 50.

3.6.4.2  The maximum number of case values in a switch statement.

There is no specific limit on the number of cases in a switch. As long as there is enough memory to hold the case information, the compiler will accept them.

3.8.1  Whether the value of a single-character character constant in a constant expression that controls conditional inclusion matches the value of the same character constant in the execution character set. Whether such a character constant can have a negative value.

All character constants, even constants in conditional directives, use the same character set (execution). Single-character character constants will be negative if the character type is signed (default and –K not requested).

3.8.2  The method for locating includable source files.

For include file names in angle brackets, if include directories are given in the command line, then the file is searched for in each of the include directories. Include directories are searched in this order:

1	In directories specified on the command line.

2	In directories specified in BCC32.CFG.

3	If no include directories are specified, search only the current directory.

3.8.2  The support for quoted names for includable source files.

For quoted includable file names, the file is searched in the following order:

1	In the same directory of the file that contains the #include statement.

2	In the directories of files that include (#include) that file.

3	The current directory.

4	Along the path specified by the /I compiler option.

5	Along paths specified by the INCLUDE environment variable.

3.8.2  The mapping of source file name character sequences.

Backslashes in include file names are treated as distinct characters, not as escape characters. Case differences are ignored for letters.

3.8.8  The definitions for _ _DATE_ _ and _ _TIME_ _ when they are unavailable.

The date and time are always available and will use the operating system date and time.

4.1.1  The decimal point character.

The decimal point character is a period (.).

4.1.5  The type of the sizeof operator, size_t.

The type size_t is unsigned.

4.1.5  The null pointer constant to which the macro NULL expands.

 NULL expands to an int zero or a long zero. Both are 32-bit signed numbers.

4.2  The diagnostic printed by and the termination behavior of the assert function.

The diagnostic message printed is “Assertion failed: expression, file filename, line nn”, where expression is the asserted expression that failed, filename is the source file name, and nn is the line number where the assertion took place.

Abort is called immediately after the assertion message is displayed.

4.3  The implementation-defined aspects of character testing and case-mapping functions.

None, other than what is mentioned in 4.3.1.

4.3.1  The sets of characters tested for by the isalnum, isalpha, iscntrl, islower, isprint and isupper functions.

First 128 ASCII characters for the default C locale. Otherwise, all 256 characters.

4.5.1  The values returned by the mathematics functions on domain errors.

An IEEE NAN (not a number).

4.5.1  Whether the mathematics functions set the integer expression errno to the value of the macro ERANGE on underflow range errors.

No, only for the other errors—domain, singularity, overflow, and total loss of precision.

4.5.6.4  Whether a domain error occurs or zero is returned when the fmod function has a second argument of zero.

No; fmod(x,0) returns 0.

4.7.1.1  The set of signals for the signal function.

SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, and SIGTERM.

4.7.1.1  The semantics for each signal recognized by the signal function.

See the description of signal.

4.7.1.1  The default handling and the handling at program startup for each signal recognized by the signal function.

See the description of signal.

4.7.1.1  If the equivalent of signal(sig, SIG_DFL); is not executed prior to the call of a signal handler, the blocking of the signal that is performed.

The equivalent of signal(sig, SIG_DFL) is always executed.

4.7.1.1  Whether the default handling is reset if the SIGILL signal is received by a handler specified to the signal function.

No, it is not.

4.9.2  Whether the last line of a text stream requires a terminating newline character.

No, none is required.

4.9.2  Whether space characters that are written out to a text stream immediately before a newline character appear when read in.

Yes, they do.

4.9.2  The number of null characters that may be appended to data written to a binary stream.

None.

4.9.3  Whether the file position indicator of an append mode stream is initially positioned at the beginning or end of the file.

The file position indicator of an append-mode stream is initially placed at the beginning of the file. It is reset to the end of the file before each write.

4.9.3  Whether a write on a text stream causes the associated file to be truncated beyond that point.

A write of 0 bytes might or might not truncate the file, depending on how the file is buffered. It is safest to classify a zero-length write as having indeterminate behavior.

4.9.3  The characteristics of file buffering.

Files can be fully buffered, line buffered, or unbuffered. If a file is buffered, a default buffer of 512 bytes is created upon opening the file.

4.9.3  Whether a zero-length file actually exists.

Yes, it does.

4.9.3  Whether the same file can be open multiple times.

Yes, it can.

4.9.4.1  The effect of the remove function on an open file.

No special checking for an already open file is performed; the responsibility is left up to the programmer.

4.9.4.2  The effect if a file with the new name exists prior to a call to rename.

Rename returns a –1 and errno is set to EEXIST.

4.9.6.1  The output for %p conversion in fprintf.

The output is eight hex digits (XXXXXXXX), zero padded, uppercase letters (the same as %08lX).

4.9.6.2  The input for %p conversion in fscanf.

See 4.9.6.1.

4.9.6.2  The interpretation of a –(hyphen) character that is neither the first nor the last character in the scanlist for a %[ conversion in fscanf.

See the description of scanf.

4.9.9.1  The value the macro errno is set to by the fgetpos or ftell function on failure.

EBADF   Bad file number.

4.9.10.4  The messages generated by perror.

Messages generated in Win32

Arg list too big	Math argument

Attempted to remove current directory	Memory arena trashed

Bad address	Name too long

Bad file number	No child processes

Block device required	No more files

Broken pipe	No space left on device

Cross-device link	No such device

Error 0	No such device or address

Exec format error	No such file or directory

Executable file in use	No such process

File already exists	Not a directory

File too large	Not enough memory

Illegal seek	Not same device

Inappropriate I/O control operation	Operation not permitted

Input/output error	Path not found

Interrupted function call	Permission denied

Invalid access code	Possible deadlock

Invalid argument	Read-only file system

Invalid data	Resource busy

Invalid environment	Resource temporarily unavailable

Invalid format	Result too large

Invalid function number	Too many links

Invalid memory block address	Too many open files

Is a directory

4.10.3  The behavior of calloc, malloc, or realloc if the size requested is zero.

calloc and malloc will ignore the request and return 0. realloc will free the block.

4.10.4.1  The behavior of the abort function with regard to open and temporary files.

The file buffers are not flushed and the files are not closed.

4.10.4.3  The status returned by exit if the value of the argument is other than zero, EXIT_SUCCESS, or EXIT_FAILURE.

Nothing special. The status is returned exactly as it is passed. The status is a represented as a signed char.

4.10.4.4  The set of environment names and the method for altering the environment list used by getenv.

The environment strings are those defined in the operating system with the SET command. putenv can be used to change the strings for the duration of the current program, but the SET command must be used to change an environment string permanently.

4.10.4.5  The contents and mode of execution of the string by the system function.

The string is interpreted as an operating system command. COMSPEC or CMD.EXE is used, and the argument string is passed as a command to execute. Any operating system built-in command, as well as batch files and executable programs, can be executed.

4.11.6.2  The contents of the error message strings returned by strerror.

See 4.9.10.4.

4.12.1  The local time zone and Daylight Saving Time.

Defined as local PC time and date.

4.12.2.1  The era for clock.

Represented as clock ticks, with the origin being the beginning of the program execution.

4.12.3.5  The formats for date and time.

 C++Builder implements ANSI formats.


Keywords

Keywords are words reserved for special purposes and must not be used as normal identifier namesPlease see the Help table of contents for a complete categorical and alphabetical listing of these and other C++Builder language elements.

[Note: This topic is retained for cross-referencing purposes only.]


Keywords (by Category)
Keyword categories

This is a categorical listing of the keywords C++Builder supports.

C++Builder extensions	keywords unique to C++Builder

C++-specific keywords	keywords recognized only in C++ programs

Modifiers	keywords that change one or more attributes of an identifier associated with an object

Operators	keywords that invoke functions against objects or identifiers

Statements	keywords that specify program control during execution

Storage class specifiers	keywords that define the location and duration of an identifier

Type specifiers	keywords that determine how memory is allocated and bit patterns are interpreted

Please see the Help table of contents for a complete categorical and alphabetical listing of C++Builder language elements.


Modifiers

A declaration uses modifiers to alter aspects of the identifier/object mapping. Please see the Help table of contents for a complete categorical and alphabetical listing of these and other C++Builder language elements.


Operator keywords

See also

Operator keywords denote operators that invoke functions against objects and identifiers. Please see the Help table of contents for a complete categorical and alphabetical listing of these and other C++Builder language elements.


Statement keywords

Statements specify the flow of control in a program. In the absence of specific jumps and selection statements, statements execute sequentially as they appear in the source code.

Please see the Help table of contents for a complete categorical and alphabetical listing of Library Routines.


asm, _asm, __asm

Example	Keywords

Category

C++Builder keyword extensions, C++-Specific Keywords

Syntax

asm <opcode> <operands> <; or newline>

_asm <opcode> <operands> <; or newline>

__asm <opcode> <operands> <; or newline>

Description

Use the asm, _asm, or __asm keyword to place assembly language statements in the middle of your C or C++ source code. Any C++ symbols are replaced by the appropriate assembly language equivalents.

You can group assembly language statements by beginning the block of statements with the asm keyword, then surrounding the statements with braces ({}).


Examples

// This example places a single assembler statement in your code:

asm pop dx

// If you want to include several of asm statements,

// surround them with braces:

asm {

  mov ax, 0x0e07

  xor bx, bx

  int 0x10         // makes the system beep

}


auto

Example	Keywords

Category

Storage class specifiers

Syntax

[auto] <data-definition> ;

Description

Use the auto modifer to define a local variable as having a local lifetime.

This is the default for local variables and is rarely used.


Example

int main()

{

  auto int i;

  i = 5;

  return i;

}


__automated

See also	Keywords	Example

Category

C++Builder keyword extensions

Syntax

_automated: <declarations>

Description

The visibility rules for automated members are identical to those of public members. The only difference between automated and public members is that OLE automation information is generated for member functions and properties that are declared in an automated section. This OLE automation type information makes it possible to create OLE Automation servers.

For a member function, the types of all member function parameters and the function result (if any) must be automatable. Likewise, for a property, the property type and the types of any array property parameters must be automatable. The automatable types are: Currency, OleVariant, DelphiInterface, double, int, float, short, String, TDateTime, Variant, and unsigned short. Declaring member functions or properties that use non-automatable types in an __automated section results in a compile-time error.

Member function declarations must use the __fastcall calling convention.

Member functions can be virtual.

Member functions may add __dispid(constant int expression) after the closing parenthesis of the parameter list.

Property declarations can only include access specifiers (__dispid, read, and write). No other specifiers (index, stored, default, nodefault) are allowed.

Property access specifiers must list a member function identifier. Data member identifiers are not allowed.

Property access member functions must use the __fastcall calling convention.

Property overrides (property declarations that don’t include the property type) are not allowed.


automated and dispid example
Example of __automated and __dispid

// Illustrates the use of __automated and __dispid.

class myclass : TAutoObject

{

// This access region is used to declare functions

// and properties that need OLE automation information.

__automated :

   // The __dispid directive associates the OLE automation

   // dispatch id 1000 with the member function.

   void __fastcall func(void)  __dispid(1000);

};


bool, false, true

See also	Example	Keywords

Category

C++-Specific Keywords

Syntax

bool <identifier>;

Description

Use bool and the literals false and true to perform Boolean logic tests.

The bool keyword represents a type that can take only the value false or true. The keywords false and true are Boolean literals with predefined values. false is numericallly zero and true is numerically one. These Boolean literals are rvalues; you cannot make an assignment to them.

You can convert an rvalue that is of type bool to an rvalue that is int type. The numerical conversion sets false to zero and true becomes one.

You can convert arithmetic, enumeration, pointer, or pointer to member rvalue types to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false. Any other value is converted to true.


Example

/* How to make Boolean tests with bool, true, and false. */

#include <iostream.h>

bool func() {    // Function returns a bool type

   return NULL;  // NULL is converted to Boolean false

// return false;  // This statement is Boolean equivalent to the one above.

   }

int main() {

   bool val = false;  // Boolean variable

   int i = 1;         // i is neither Boolean-true nor Boolean-false

   int *iptr = 0;     // null pointer

   float j = 1.01;    // j is neither Boolean-true nor Boolean-false

   // Tests on integers

   if (i == true)  cout << "True: value is 1" << endl;

   if (i == false) cout << "False: value is 0" << endl;

 // Test on pointer

   if (iptr == false) cout << "Invalid pointer." << endl;

   // To test j's truth value, cast it to bool type.

   if (bool(j) == true) cout << "Boolean j is true." << endl;

   // Test Boolean function return value

   val = func();

   if (val == false)

      cout << "func() returned false.";

   if (val == true)

      cout << "func() returned true.";

   return false;  // false is converted to 0

}

Program output

True: value is 1

Unknown truth value for g.

Invalid pointer.

Boolean j is true.

func() returned false.


break

See also	Example	Keywords

Category

Statements

Syntax

break ;

Description

Use the break statement within loops to pass control to the first statement following the innermost switch, for, while, or do block.


Example

/* Illustrates the use of keywords break, case, default, and switch. */

#include <conio.h>

#include <stdio.h>

int main(void) {

   int ch;

   printf("\tPRESS a, b, OR c. ANY OTHER CHOICE WILL "

          "TERMINATE THIS PROGRAM.");

   for ( /* FOREVER */; ((ch = getch()) != EOF); )

      switch (ch) {

         case 'a' :    /* THE CHOICE OF a HAS ITS OWN ACTION. */

            printf("\nOption a was selected.\n");

            break;

         case 'b' :    /* BOTH b AND c GET THE SAME RESULTS. */

         case 'c' :

            printf("\nOption b or c was selected.\n");

            break;

         default :

            printf("\nNOT A VALID CHOICE!  Bye ...");

            return(-1);

         }

   return(0);

   }


case

See also	Example	Keywords

Category

Statements

Syntax

switch ( <switch variable> ){

  case <constant expression> : <statement>; [break;]

    .

    .

    .

  default : <statement>;

}

Description

Use the case statement in conjunction with switches to determine which statements evalute.

The list of possible branch points within <statement> is determined by preceding substatements with

case <constant expression> : <statement>;

where <constant expression> must be an int and must be unique.

The <constant expression> values are searched for a match for the <switch variable>.

If a match is found, execution continues after the matching case statement until a break statement is encountered or the end of the switch statement is reached.

If no match is found, control is passed to the default case.

Note:	It is illegal to have duplicate case constants in the same switch statement.


catch

See also	Keywords

Category

Statements, C++-Specific Keywords

Syntax

catch (exception-declaration) compound-statement

Description

The exception handler is indicated by the catch keyword. The handler must be used immediately after the statements marked by the try keyword. The keyword catch can also occur immediately after another catch. Each handler will only evaluate an exception that matches, or can be converted to, the type specified in its argument list.


cdecl, _cdecl, __cdecl

Example	Keywords

Category

Modifiers, C++Builder keyword extensions

Syntax

cdecl <data/function definition> ;

_cdecl <data/function definition> ;

__cdecl <data/function definition> ;

Description

Use a cdecl, _cdecl, or __cdecl modifier to declare a variable or a function using the C-style naming conventions (case-sensitive, with a leading underscore appended). When you use cdecl, _cdecl, or __cdecl in front of a function, it effects how the parameters are passed (parameters are pushed right to left, and the caller cleans up the stack). The __cdecl modifier overrides the compiler directives and IDE options.

The cdecl, _cdecl, and __cdecl keywords are specific to C++Builder.


Example

int __cdecl FileCount;

long __cdecl HisFunc(int x);


char

See also	Keywords

Category

Type specifiers

Syntax

[signed|unsigned] char <variable_name>

Description

Use the type specifier char to define a character data type. Variables of type char are 1 byte in length.

A char can be signed, unsigned, or unspecified. By default, signed char is assumed.

Objects declared as characters (char) are large enough to store any member of the basic ASCII character set.


class

See also	Example	Keywords

Category

C++-Specific Keywords, Type specifiers

Syntax

<classkey> <classname> <baselist> { <member list> }

<classkey> is either a class, struct, or union.

<classname> can be any name unique within its scope.

<baselist> lists the base class(es) that this class derives from. <baselist> is optional

<member list> declares the class's data members and member functions.

Description

Use the class keyword to define a C++ class.

Within a class:

the data are called data members

the functions are called member functions


Example

class stars {

   int magnitude;       // Data member

   int starfunc(void);  // Member function

};


__classid

See also	Keywords

Category

Operators, C++Builder keyword extensions

Syntax

__classid(classType)

Description

The __classid operator was added to support the VCL. This operator should not normally be directly used by C++Builder programmers. For more information, see the keyword extensions.


__closure

See also	Keywords

Category

C++Builder keyword extensions

Syntax

<type> ( __closure * <id> ) (<param list>);

Description

The keyword __closure was added to support the VCL and is used when declaring event handler functions. For more information, see the keyword extensions.


const

See also	Example	Keywords

Category

Modifiers

Syntax

const <variable name> [ = <value> ] ;

<function name> ( const <type>*<variable name> ;)

<function name> const;

Description

Use the const modifier to make a variable value unmodifiable.

Use the const modifier to assign an initial value to a variable that cannot be changed by the program. Any future assignments to a const result in a compiler error.

A const pointer cannot be modified, though the object to which it points can be changed. Consider the following examples.

   const float pi   = 3.14;

   const  maxint  = 12345;   // When used by itself, const is equivalent to int.

   char *const str1 = "Hello, world";           // A constant pointer

   char const *str2 = "Borland International";  // A pointer to a constant character string.

Given these declarations, the following statements are illegal.

pi   = 3.0;         // Assigns a value to a const.

i     = maxint++;   // Increments a const.

str1 = "Hi, there!" // Points str1 to something else.

Using the const Keyword in C++ Programs

C++ extends const to include classes and member functions. In a C++ class definition, use the const modifier following a member function declaration. The member function is prevented from modifying any data in the class.

A class object defined with the const keyword attempts to use only member functions that are also defined with const. If you call a member function that is not defined as const, the compiler issues a warning that the a non-const function is being called for a const object. Using the const keyword in this manner is a safety feature of C++.

Warning:	A pointer can indirectly modify a const variable, as in the following:

*(int *)&my_age = 35;

If you use the const modifier with a pointer parameter in a function's parameter list, the function cannot modify the variable that the pointer points to. For example,

int printf (const char *format, ...);

printf is prevented from modifying the format string.

Example

class X  {

   int j;

public:

  X::X() { j = 0; };

  int lowerBound() const;            // DOES NOT MODIFY ANY DATA MEMBERS

  int dimension(X x1, const X &x2) { // x2 PARAMETER WON'T BE MODIFIED

     x1.j = 3;       // OKAY; x1 OBJECT IS MODIFIABLE

     x2.j = 5;       // ERROR; x2 IS NOT MODIFIABLE

     return x2.j;

     }

};

Example 2

#include <iostream.h>

class Alpha {

   int num;

public:

   Alpha(int j = 0) { num = j; }

   int func(int i) const {

      cout << "Non-modifying function." << endl;

      return i++;

      }

   int func(int i) {

      cout << "Modify private data" << endl;

      return num = i;

      }

   int f(int i) { cout << "Non-const function called with i = " << i << endl; return i;}

};

void main() {

   Alpha alpha_mod;         // Calls the non-const functions.

   const Alpha alpha_inst;  // Attempts to call the const functions.

   alpha_mod.func(1);

   alpha_mod.f(1);          // Causes a compiler warning.

   alpha_inst.func(1);

   alpha_inst.f(1);

   }

Output:

Modify private data

Non-const function called with i = 1

Non-modifying function.

Non-const function called with i = 1


continue

See also	Example	Keywords

Category

Statements

Syntax

continue ;

Description

Use the continue statement within loops to pass control to the end of the innermost enclosing end brace belonging to a looping construct, sych as for or while; at which point the loop continuation condition is re-evaluated.


Example

void main ()

{

  for (i = 0; i < 20; i++) {

     if (array[i] == 0)

       continue;

     array[i] = 1/array[i];

  }

}


__declspec

See also	Example	Keywords

Category

Modifiers, C++Builder keyword extensions, Storage class specifiers

Syntax

__declspec(<decl-modifier>)

Description

For a list of __declspec keyword arguments used for the VCL, see VCL class declarations.

Use the __declspec keyword to indicate the storage class attributes for a variable or function.

The __declspec keyword extends the attribute syntax for storage class modifiers so that their placement in a declarative statement is more flexible. The __declspec keyword and its argument can appear anywhere in the declarator list, as opposed to the old-style modifiers which could only appear immediately preceding the identifier to be modified.

__export void f(void);                      // illegal

void __export f(void)                       // correct

void __declspec(dllexport) f(void);         // correct

__declspec(dllexport)void f(void);          // correct

class __declspec(dllexport) ClassName { }   // correct

In addition to the VCL-related arguments listed above, the decl-modifier argument can be one of dllexport, dllimport, thread or naked. The thread attribute affects data and objects only. The naked attribute affects functions only. The dllimport and dllexport attributes affect functions, data, and objects.

Use of the naked argument suppresses the prolog/epilog code. Be aware when using __declspec(naked) that it does not set up a normal stack frame. A function with __declspec(naked) will not preserve the register values that are normally preserved.  It is the programmer's responsibility to conform to whatever conventions the caller of the function expects.

The meaning of the remaining arguments is equivalent to the following storage class attribute keywords.

Argument	Comparable keyword

dllexport	__export

dllimport	__import

thread	__thread


Example

/* Examples of  __declspec declarations follow. */

__declspec(dllimport) void func(void);

__declspec(dllimport) int a;

__declspec(dllexport) void bar (void);

/** Use thread argument only with static storage data. **/

__declspec(thread) int th;

int __declspec(thread) th1;


Example of declspec
Using __declspec in VCL class declarations

For a list of VCL specific arguments to __declspec, see the __declspec keyword extension.


default

See also	Example	Keywords

Category

Statements

Syntax

switch ( <switch variable> ){

  case <constant expression> : <statement>; [break;]

    .

    .

    .

  default : <statement>;

}

Description

Use the default statement in switch statement blocks.

If a case match is not found and the default statement is found within the switch statement, the execution continues at this point.

If no default is defined in the switch statement, control passes to the next statement that follows the switch statement block.


__dispid

See also	Keywords	Example

Category

Modifiers

Syntax

__dispid(constant int expression)

Description

A member function that has been declared in the __automated section of a class can  include an optional __dispid(constant int expression) directive. The directive must be declared after the closing parenthesis of the parameter list.

The constant int expression gives the OLE Automation dispatch ID of the member function or property. If a dispid directive is not used, the compiler automatically picks a number one larger than the largest dispatch ID used by any member function or property in the class and its base classes.

Specifying an already-used dispatch ID in a dispid directive causes a compile-time error.


do

See also	Example	Keywords

Category

Statements

Syntax

do <statement> while ( <condition> );

Description

The do statement executes until the condition becomes false.

<statement> is executed repeatedly as long as the value of <condition> remains true.

Since the conditon tests after each the loop executes the <statement>, the loop will execute at least once.


do Example

/* This example prompts users for a password  */

/* and continued to prompt them until they    */

/* enter one that matches the value stored in */

/* checkword.                                 */

#include <stdio.h>

#include <string.h>

int main ()

{

  char checkword[80] = "password";

  char password[80]  = "";

  do {

    printf ("Enter password: ");

    scanf("%s", password);

  } while (strcmp(password, checkword));

  return 0;

}


double

See also	Keywords

Category

Type specifiers

Syntax

[long] double <identifier>

Description

Use the double type specifier to define an identifier to be a floating-point data type. The optional modifier long extends the accuracy of the floating-point value.

If you use the double keyword, the C++Builder IDE will automatically link the floating-point math package into your program.


enum

See also	Example	Keywords

Category

Type specifiers

Syntax

enum [<type_tag>] {<constant_name> [= <value>], ...} [var_list];

<type_tag> is an optional type tag that names the set.

<constant_name> is the name of a constant that can optionally be assigned the value of <value>. These are also called enumeration constants.

<value> must be an integer. If <value> is missing, it is assumed to be:

<prev> + 1

where <prev> is the value of the previous integer constant in the list. For the first integer constant in the list, the default value is 0.

<var_list> is an optional variable list that assigns variables to the enum type.

Description

Use the enum keyword to define a set of constants of type int, called an enumeration data type.

An enumeration data type provides mnemonic identifiers for a set of integer values. Use the -b flag to toggle the Treat Enums As Ints option. .Enums are always interpreted as ints if the range of values permits this, but if they are not ints the value gets promoted to an int in expressions. Depending on the values of the enumerators, identifiers in an enumerator list are implicitly of type signed char, unsigned char, short, unsigned short, int, or unsigned int.

In C, an enumerated variable can be assigned any value of type int--no type checking beyond that is enforced. In C++, an enumerated variable can be assigned only one of its enumerators.

In C++, lets you omit the enum keyword if <tag_type> is not the name of anything else in the same scope. You can also omit <tag_type> if no further variables of this enum type are required.

In the absence of a <value> the first enumerator is assigned the value of zero. Any subsequent names without initializers will then increase by one. <value> can be any expression yielding a positive or negative integer value (after possible integer promotions). These values are usually unique, but duplicates are legal.

Enumeration tags share the same name space as structure and union tags. Enumerators share the same name space as ordinary variable identifiers.

In C++, enumerators declared within a class are in the scope of that class.


Examples

enum days { sun, mon, tues, wed, thur, fri, sat } anyday;

establishes a unique integral type, enum days, a variable anyday of this type, and a set of enumerators (sun, mon,...) with constant integer values.

enum modes { LASTMODE = -1, BW40=0, C40, BW80, C80, MONO = 7 };

/*

   "modes" is the type tag.

   "LASTMODE", "BW40", "C40", etc. are the constant names.

   The value of C40 is 1 (BW40 + 1); BW80 = 2 (C40 + 1), etc.

*/


__except

See also	Keywords

Category

Statements, C++Builder keyword extensions

Syntax

__except (expression) compound-statement

Description

The __except keyword specifies the action that should be taken when the exception specified by expression has been raised.


explicit

See also

Category

C++-Specific Keywords

Syntax

explicit <single-parameter constructor declaration>

Description

Normally, a class with a single-parameter constructor can be assigned a value that matches the constructor type. This value is automatically (implicitly) converted into an object of the class type to which it is being assigned. You can prevent this kind of implicit conversion from occurring by declaring the constructor of the class with the explicit keyword. Then all objects of that class must be assigned values that are of the class type; all other assignments result in a compiler error.

Objects of the following class can be assigned values that match the constructor type or the class type:

class X {

public:

  X(int);

  X(const char*, int = 0);

};

Then, the following assignment statements are legal.

void f(X arg) {

  X a = 1;

  X B = "Jessie";

  a = 2;

}

However, objects of the following class can be assigned values that match the class type only:

class X {

public:

  explicit X(int);

  explicit X(const char*, int = 0);

};

The explicit constructors then require the values in the following assignment statements to be converted to the class type to which they are being assigned.

void f(X arg) {

  X a = X(1);

  X b = X("Jessie",0);

  a = X(2);

}


export

See also	Keywords

Category

Unimplemented

Syntax

export template < template-parameter-list > declaration

Description

The export keyword is reserved for future implementation, but has no effect in this release.


_export, __export

See also	Keywords

Category

Modifiers, C++Builder keyword extensions

Form 1

class _export <class name>

Form 2

return_type _export <function name>

Form 3

data_type _export <data name>

Description

These modifiers are used to export classes, functions, and data.

The linker enters functions flagged with _export or __export into an export table for the module.

Using _export or __export eliminates the need for an EXPORTS section in your module definition file.

Functions that are not modified with _export or __export receive abbreviated prolog and epilog code, resulting in a smaller object file and slightly faster execution.

Note:	If you use _export or __export to export a function, that function will be exported by name rather than by ordinal (ordinal is usually more efficient).

If you want to change various attributes from the default, you'll need a module definition file.


Compiler Options and the _export Keyword
Compiler Options and the __export Keyword

See also	Keywords

This table summarizes the effect of the combination of various Windows options and the __export keyword:

The compiler option is: *	-tW·or -tWD	-tWE·or -tWDE	-tW·or -tWD	-tWE·or -tWDE	-tW·or -tWD	-tWE·or -tWDE	-tW·or -tWD	-tWE·or -tWDE
Function flagged with __export?	Yes	Yes	Yes	Yes	No	No	No	No
Function·listed in EXPORTS?	Yes	Yes	No	No	Yes	Yes	No	No
Is·function exportable?	Yes	Yes	Yes	Yes	Yes	No	Yes	No
Will function be exported?	Yes	Yes	Yes	Yes	Yes	Yes	No	No
* Or the 32-bit console-mode application equivalents.


Exportable Functions in DLLs

See also

There are two ways to compile a function f1( ) in a DLL as exportable and then export it.

Compile the DLL with all functions exportable and list f1( ) in the EXPORTS section of the module definition file, or

Flag the function f1( ) with the _export keyword.


Using _export with C++ Classes

See also	Keywords

Whenever you declare a class as _export, the compiler exports all of its non-inline member functions and static data members.

If you declare the class in an include file that is included in both the DLL source files and the source files of the application that use the DLL, declare the class as _export when compiling the DLL

To do this, use the __DLL__ macro, which the compiler defines when it's building a DLL.


extern

See also	Example	Keywords

Category

Storage class specifiers

Syntax

extern <data definition> ;

[extern] <function prototype> ;

Description

Use the extern modifier to indicate that the actual storage and initial value of a variable, or body of a function, is defined in a separate source code module. Functions declared with extern are visible throughout all source files in a program, unless you redefine the function as static.

The keyword extern is optional for a function prototype.

Use extern "c" to prevent function names from being mangled in C++ programs.


Examples

extern int _fmode;

extern void Factorial(int n);

extern "c" void cfunc(int);


Parameter Types and Possible Registers Used

The compiler uses the following rules when deciding which parameters are to be passed in registers.

Parameter Type	Registers

char (signed and unsigned)	al, dl, cl

short (signed and unsigned)	AX, DX, CX

int/long (signed and unsigned)	EAX, EDX, ECX

Only three parameters can be passed in registers to any one function.

Do not assume the assignment of registers will reflect the ordering of the parameters to a function. Union, structure, and floating-point (float, double, and long double) parameters are pushed on the stack.


_fastcall, __fastcall

See also	Keywords

Category

Modifiers, C++Builder keyword extensions

Syntax

return-value _fastcall function-name(parm-list)

return-value __fastcall function-name(parm-list)

Description

Use the __fastcall modifier to declare functions that expect parameters to be passed in registers. The first three parameters are passed (from left to right) in EAX, EDX, and ECX, if they fit in the register. The registers are not used if the parameter is a floating-point or struct type.

All form class member functions must use the __fastcall convention.

The compiler treats this calling convention as a new language specifier, along the lines of _cdecl and _pascal

Functions declared using _cdecl or _pascal cannot also have the _fastcall modifiers because they use the stack to pass parameters. Likewise, the __fastcall modifier cannot be used together with _export.

The compiler prefixes the __fastcall function name with an at-sign ("@"). This prefix applies to both unmangled C function names and to mangled C++ function names.

Note:	The __fastcall modifier is subject to name mangling. See the description of the -VC option.


__finally

See also	Keywords

Category

Statements, C++Builder keyword extensions

Syntax

__finally {compound-statement}

Description

The __finally keyword specifies actions that should be taken regardless of how the flow within the preceding __try exits.

The following is the code fragment shows how to use the try/__finally construct:

#include <stdio.h>

#include <string.h>

#include <windows.h>

class Exception

{

  public:

  Exception(char* s = "Unknown"){what = strdup(s);      }

  Exception(const Exception& e ){what = strdup(e.what); }

 ~Exception()                   {free(what);         }

  char* msg() const             {return what;           }

private:

  char* what;

};

int main()

{

  float e, f, g;

try

  {

    try

    {

      f = 1.0;

      g = 0.0;

      try

      {

        puts("Another exception:");

        e = f / g;

      }

      __except(EXCEPTION_EXECUTE_HANDLER)

      {

        puts("Caught a C-based exception.");

        throw(Exception("Hardware error: Divide by 0"));

      }

    }

    catch(const Exception& e)

    {

      printf("Caught C++ Exception: %s :\n", e.msg());

    }

  }

  __finally

  {

    puts("C++ allows __finally too!");

  }

return e;

}

Running the above program results in the following:

Another exception:

Caught a C-based exception.

Caught C++ exception[Hardware error: Divide by 0]

C++ allows __finally too!


float

See also	Keywords

Category

Type specifiers

Syntax

float <identifier>

Description

Use the float type specifier to define an identifier to be a floating-point data type.

Type	Length	Range

float	32 bits 	3.4 * (10**-38) to 3.4 * (10**+38)

The C++Builder IDE automatically links the floating-point math package into you program if you use floating-point values or operators.


for

Example	Keywords

Category

Statements

Syntax

for ( [<initialization>] ; [<condition>] ; [<increment>] )  <statement>

Description

The for statement implements an iterative loop.

<condition> is checked before the first entry into the block.

<statement> is executed repeatedly UNTIL the value of <condition> is false.

Before the first iteration of the loop, <initialization> initializes variables for the loop.

After each iteration of the loop, <increments> increments a loop counter. Consequently, j++ is functionally the same as ++j.

In C++, <initialization> can be an expression or a declaration.

The scope of any identifier declared within the for loop extends to the end of the control statement only.

A variable defined in the for-initialization expression is in scope only within the for-block. See the description of the -Vd option.

All the expressions are optional. If <condition> is left out, it is assumed to be always true.


Examples

// An example of the scope of variables in for-expressions.

// The example compiles if you use the -Vd option.

#include <iostream.h>

int main() {

   for (int i = 0; i < 10; i++)

      if (i == 8)

      cout << "\ni = " << i;

return i;  // Undefined symbol ‘i’ in function main().

}


friend

Example	Keywords

Category

C++-Specific Keywords

Syntax

friend <identifier>;

Description

Use friend to declare a function or class with full access rights to the private and protected members of the class, without being a member of that class. The outside class has fill access to the class that declares that outside class a friend.

In all other respects, the friend is a normal function in terms of scope, declarations, and definitions.


Example

class stars {

   friend class galaxy;

   int magnitude;

   int starfunc(void);

};

class galaxy {

   long int number_of_stars;

   void stars_magnitude(stars&);

   void stars_func(stars*);

}


goto

Example	Keywords

Category

Statements

Syntax

goto <identifier> ;

Description

Use the goto statement to transfer control to the location of a local label specified by <identifier>.

Labels are always terminated by a colon.


Example

Again:       /* this is the label */

;

.

.

.

goto Again;


if, else

See also	Example	Keywords

Category

Operators

Syntax

if ( <condition> )  <statement1>;

if ( <condition> )  <statement1>;

else  <statement2>;

Description

Use if to implement a conditional statement.

You can declare variables in the condition expression. For example,

   if (int val = func(arg))

is valid syntax. The variable val is in scope for the if statement and extends to an else block when it exists.

The condition statement must convert to a bool type. Otherwise, the condition is ill-formed.

When <condition> evaluates to true, <statement1> executes.

If <condition> is false, <statement2> executes.

The else keyword is optional, but no statements can come between an if statement and an else.

The #if and #else preprocessor statements (directives) look similar to the if and else statements, but have very different effects. They control which source file lines are compiled and which are ignored.


Examples

if (int val = func(count)) { /* statements */ }

else {

   /* take other action */

   cout << "val is false"

   }


_import, __import

Keywords

Category

Modifiers, C++Builder keyword extensions

Form 1

class _import <class name>

class __import <class name>

Form 2

return_type _import <function name>

return_type __import <function name>

Form 3

data_type _import <data name>

data_type __import <data name>

Description

This keyword can be used as a class, function, or data modifier in 32-bit programs.


__inline

Keywords

Category

C++Builder keyword extensions

Syntax

__inline <datatype> <class>_<function> (<parameters>) { <statements>; }

Description

Use the __inline keyword to declare or define C or C++ inline functions. The behavior of the __inline keyword is identical to that of the inline keyword, which is only supported in C++.

Inline functions are best reserved for small, frequently used functions.


inline

Example	Keywords

Category

C++-Specific Keywords

Syntax

inline <datatype> <class>_<function> (<parameters>) { <statements>; }

Description

Use the inline keyword to declare or define C++ inline functions.

Inline functions are best reserved for small, frequently used functions.


Example

inline char* cat_func(void) { return char*; }


int

See also	Keywords

Category

Type specifiers

Syntax

[signed|unsigned] int <identifier> ;

Description

Use the int type specifier to define an integer data type.

Variables of type int can be signed (default) or unsigned.


long

See also	Keywords

Category

Type specifiers

Syntax

long [int] <identifier> ;

[long] double <identifier> ;

Description

When used to modify an int, it doubles the number of bytes available to store the integer value.

When used to modify a double, it defines a floating-point data type with 80 bits of precision instead of 64.

The C++Builder IDE links the floating-point math package if you use floating-point values or operators anywhere in your program.


mutable

See also	Example	Keywords

Category

C++-Specific Keywords, Storage class specifiers

Syntax

mutable <variable name>;

Description

Use the mutable specifier to make a variable modifiable even though it is in a const-qualified expression.

Using the mutable Keyword

Only class data members can be declared mutable. The mutable keyword cannot be used on static or const names. The purpose of mutable is to specify which data members can be modified by const member functions. Normally, a const member function cannot modify data members.


Example

#include <iostream.h>

class Alpha {

   mutable int count;

   mutable const int* iptr;

public:

   int func1(int i = 0) const { // Promises not to change const arguments.

      count = i++;  // But count can be changed.

      iptr = &i;

      cout << *iptr;

      return count;

      }

};

int main(void) {

   Alpha a;

   a.func1(0);

   return 0;

   }


operator

See also	Example	Keywords

Category

Operators, C++-Specific Keywords

Syntax

operator <operator symbol>( <parameters> )

{

   <statements>;

}

Description

Use the operator keyword to define a new (overloaded) action of the given operator. When the operator is overloaded as a member function, only one argument is allowed, as *this is implicitly the first argument.

When you overload an operator as a friend, you can specify two arguments.


pascal, _pascal, __pascal

Keywords

Category

Modifiers, C++Builder keyword extensions

Syntax

pascal <data-definition/function-definition> ;

_pascal <data-definition/function-definition> ;

__pascal <data-definition/function-definition> ;

Description

Use the pascal, _pascal, and __pascal keywords to declare a variable or a function using a Pascal-style naming convention (the name is in uppercase).

In addition, pascal declares Pascal-style parameter-passing conventions when applied to a function header (parameters pushed left ot right; the called function cleans up the stack).

In C++ programs, functions declared with the pascal modifer will still be mangled.


private

See also	Keywords

Category

C++-Specific Keywords

Syntax

private: <declarations>

Description

A private member can be accessed only by member functions and friends of the class in which it is declared.

Class members are private by default.

You can override the default struct access with private or protected but you cannot override the default union access.

Friend declarations are not affected by these access specifiers.


protected

See also	Keywords

Category

C++-Specific Keywords

Syntax

protected: <declarations>

Description

A protected member can be accessed by member functions and friends of the class in which it was declared, and by classes derived from the declared class.

You can override the default struct access with private or protected but you cannot override the default union access.

Friend declarations are not affected by these access specifiers.


public

See also	Keywords

Category

C++-Specific Keywords

Syntax

public: <declarations>

Description

A public member can be accessed by any function.

Members of a struct or union are public by default.

You can override the default struct access with private or protected but you cannot override the default union access.

Friend declarations are not affected by these access specifiers.


__property

See also	Keywords

Category

C++Builder keyword extensions

Syntax

<property declaration> ::=

      __property <type> <id> [ <prop dim list> ] = "{" <prop attrib list> "}"

  <prop dim list> ::= "[" <type> [ <id> ] "]" [ <prop dim list> ]

  <prop attrib list> ::= <prop attrib> [ , <prop attrib list> ]

  <prop attrib> ::=     read = <data/function id>

  <prop attrib> ::=     write = <data/function id>

  <prop attrib> ::=     stored = <data/function id>

  <prop attrib> ::=     stored = <boolean constant>

  <prop attrib> ::=     default = <constant>

  <prop attrib> ::=     nodefault

  <prop attrib> ::=     index = <const int expression>

Description

The __property keyword was added to support the VCL. For more information, see the keyword extensions.


__published

See also	Keywords

Category

C++Builder keyword extensions

Syntax

__published: <declarations>

Description

The __published keyword was added to support the VCL.  For more information, see the keyword extensions.


register

Example	Keywords

Category

Storage class specifiers

Syntax

register <data definition> ;

Description

Use the register storage class specifier to store the variable being declared in a CPU register (if possible), to optimize access and reduce code.

Note: The C++Builder compiler can ignore requests for register allocation. Register allocation is based on the compiler’s analysis of how a variable is used.


Example

register int i;


return

Example	Keywords

Category

Statements

Syntax

return [ <expression> ] ;

Description

Use the return statement to exit from the current function back to the calling routine, optionally returning a value.


Example

double sqr(double x)

{

  return (x*x);

}


short

See also	Example	Keywords

Category

Type specifiers

Syntax

short int <variable> ;

Description

Use the short type modifier when you want a variable smaller than an int. This modifier can be applied to the base type int.

When the base type is omitted from a declaration, int is assumed.


Examples

short int i;

short     i;    /* same as "short int i;" */


signed

See also	Example	Keywords

Category

Type specifiers

Syntax

signed <type> <variable> ;

Description

Use the signed type modifier when the variable value can be either positive or negative. The signed modifier can be applied to base types int, char, long, short, and __int64.

When the base type is omitted from a declaration, int is assumed.


Example

signed   int       i;    /* signed is default        */

signed             i;    /* same as "signed int i;"  */

unsigned long int  l;    /* int OK, not needed       */

signed   char      ch;   /* unsigned is default      */


size_t

In Borland’s implementation of the ANSI C standard, the type size_t is unsigned.


sizeof

See also	Example	Operators

Category

Operators

Description

The sizeof operator has two distinct uses:

sizeof unary-expression

sizeof (type-name)

The result in both cases is an integer constant that gives the size in bytes of how much memory space is used by the operand (determined by its type, with some exceptions). The amount of space that is reserved for each type depends on the machine.

In the first use, the type of the operand expression is determined without evaluating the expression (and therefore without side effects). When the operand is of type char (signed or unsigned), sizeof gives the result 1. When the operand is a non-parameter of array type, the result is the total number of bytes in the array (in other words, an array name is not converted to a pointer type). The number of elements in an array equals sizeof array/ sizeof array[0] .

If the operand is a parameter declared as array type or function type, sizeof gives the size of the pointer. When applied to structures and unions, sizeof gives the total number of bytes, including any padding.

You cannot use sizeof with expressions of function type, incomplete types, parenthesized names of such types, or with an lvalue that designates a bit field object.

The integer type of the result of sizeof is size_t.

You can use sizeof in preprocessor directives; this is specific to C++Builder.

In C++, sizeof(classtype), where classtype is derived from some base class, returns the size of the object (remember, this includes the size of the base class).

Example for sizeof operator

/*  USE THE sizeof OPERATOR TO GET SIZES OF DIFFERENT DATA TYPES. */

#include <stdio.h>

struct st {

   char *name;

   int age;

   double height;

      };

struct st St_Array[]= {  /* AN ARRAY OF structs */

   { "Jr.",     4,  34.20 },  /* ST_Array[0] */

   { "Suzie",  23,  69.75 },  /* ST_Array[1] */

   };

int main() {

   long double LD_Array[] = { 1.3, 501.09, 0.0007, 90.1, 17.08 };

   printf("\nNumber of elements in LD_Array = %d",

           sizeof(LD_Array) / sizeof(LD_Array[0]));

   /****  THE NUMBER OF ELEMENTS IN THE ST_Array. ****/

   printf("\nSt_Array has %d elements",

           sizeof(St_Array)/sizeof(St_Array[0]));

   /****  THE NUMBER OF BYTES IN EACH ST_Array ELEMENT.  ****/

   printf("\nSt_Array[0] = %d", sizeof(St_Array[0]));

   /****  THE TOTAL NUMBER OF BYTES IN ST_Array.  ****/

      printf("\nSt_Array=%d", sizeof(St_Array));

   return 0;

   }

Output

Number of elements in LD_Array = 5

St_Array has 2 elements

St_Array[0] = 16

St_Array= 32


static

Example	Keywords

Category

Storage class specifiers

Syntax

static <data definition> ;

static <function name> <function definition> ;

Description

Use the static storage class specifier with a local variable to preserve the last value between successive calls to that function. A static variable acts like a local variable but has the lifetime of an external variable.

In a class, data and member functions can be declared static. Only one copy of the static data exists for all objects of the class.

A static member function of a global class has external linkage. A member of a local class has no linkage. A static member function is associated only with the class in which it is declared. Therefore, such member functions cannot be virtual.

Static member functions can only call other static member functions and only have access to static data. Such member functions do not have a this pointer.


Examples

static int i;

static void printnewline(void) {}


_stdcall, __stdcall

Keywords

Category

Modifiers, C++Builder keyword extensions

Syntax

__stdcall <function-name>

_stdcall <function-name>

Description

The _stdcall and __stdcall keywords force the compiler to generate function calls using the Standard calling convention. Functions must pass the correct number and type of arguments; this is unlike normal C use, which permits a variable number of function arguments. Such functions comply with the standard WIN32 argument-passing convention.

Note:	The __stdcall modifier is subject to name mangling. See the description of the -VC option.


struct

See also	Example	Keywords

Category

Type specifiers

Syntax

struct [<struct type name>] {

  [<type> <variable-name[, variable-name, ...]>] ;

    .

    .

    .

} [<structure variables>] ;

Description

Use a struct to group variables into a single record.

<struct type name>	An optional tag name that refers to the structure type.

<structure variables>	The data definitions, also optional.

Though both <struct type name> and <structure variables> are optional, one of the two must appear.

You define elements in the record by naming a <type>, followed by one or more <variable-name> (separated by commas).

Separate different variable types by a semicolon.

To access elements in a structure, use a record selector (.) or ->.

To declare additional variables of the same type, use the keyword struct followed by the <struct type name>, followed by the variable names. In C++ the keyword struct can be omitted.

Note: C++Builder allows the use of anonymous struct embedded within another structure.


Example

#include <string.h>

struct my_struct {

  char name[80], phone_number[80];

  int  age, height;

} my_friend;

void func() {

   strcpy(my_friend.name,"Mr. Wizard");   /* accessing an element */

}

struct my_struct my_friends[100];   /* declaring additional variables */


switch

See also	Example	Keywords

Category

Statements

Syntax

switch ( <switch variable> ) {

  case <constant expression> : <statement>; [break;]

    .

    .

    .

  default : <statement>;

}

Description

Use the switch statement to pass control to a case which matches the <switch variable>. At which point the statements following the matching case evaluate.

If no case satisfies the condition the default case evaluates.

To avoid evaluating any other cases and reliquish control from the switch, terminate each case with break;.


Example

/* Illustrates the use of keywords break, case, default, and switch. */

#include <conio.h>

#include <stdio.h>

int main(void) {

   int ch;

   printf("\tPRESS a, b, OR c. ANY OTHER CHOICE WILL "

          "TERMINATE THIS PROGRAM.");

   for ( /* FOREVER */; ((ch = getch()) != EOF); )

      switch (ch) {

         case 'a' :    /* THE CHOICE OF a HAS ITS OWN ACTION. */

            printf("\nOption a was selected.\n");

            break;

         case 'b' :    /* BOTH b AND c GET THE SAME RESULTS. */

         case 'c' :

            printf("\nOption b or c was selected.\n");

            break;

         default :

            printf("\nNOT A VALID CHOICE!  Bye ...");

            return(-1);

         }

   return(0);

   }


this

See also	Keywords

Category

C++-Specific Keywords

Syntax

class X {

int a;

public:

X (int b) {this -> a = b;}

};

Description

In nonstatic member functions, the keyword this is a pointer to the object for which the function is called. All calls to nonstatic member functions pass this as a hidden argument.

this is a local variable available in the body of any nonstatic member function. Use it implicitly within the function for member references. It does not need to be declared and it is rarely referred to explicitly in a function definition.

For example, in the call x.func(y) , where y is a member of X, the keyword this is set to &x and y is set to this->y, which is equivalent to x.y.

Static member functions do not have a this pointer because they are called with no particular object in mind. Thus, a static member function cannot access nonstatic members without explicitly specifying an object with . or ->.


throw

See also	Keywords

Category

Statements, C++-Specific Keywords

Syntax

throw assignment-expression

Description

When an exception occurs, the throw expression initializes a temporary object of the type T (to match the type of argument arg) used in throw(T arg). Other copies can be generated as required by the compiler. Consequently, it can be useful to define a copy constructor for the exception object.


__try

See also	Keywords

Category

Statements, C++Builder keyword extensions

Syntax

__try compound-statement handler-list

__try compound-statement termination-statement

Description

The __try keyword is supported in both C and C++ programs. You can also use try in C++ programs.

A block of code in which an exception can occur must be prefixed by the keyword __try. Following the try keyword is a block of code enclosed by braces. This indicates that the program is prepared to test for the existence of exceptions. If an exception occurs, the normal program flow is interrupted. The program begins a search for a handler that matches the exception. If the exception is generated in a C module, it is possible to handle the structured exception in either a C module or a C++ module.

If a  handler can be found for the generated structured exception, the following actions can be taken:

Execute the actions specified by the handler

Ignore the generated exception and resume program execution

Continue the search for some other handler (regenerate the exception)

If no handler is found, the program will call the terminate function. If no exceptions are thrown, the program executes in the normal fashion.


__try example
// try example

// In PROG.C

void func(void) {

   // generate an exception

   RaiseException( /* specify your arguments */ );

}

// In CALLER.CPP

// How to test for C++ or C-based exceptions.

#include <excpt.h>

#include <iostream.h>

int main(void) {

   try

   {            // test for C++ exceptions

      try

      {         // test for C-based structured exceptions

         func();

      }

      __except( /* filter-expression */ )

      {

      cout << "A structured exception was generated.";

      /* specify actions to take for this structured exception */

      return -1;

      }

      return 0;

   }

   catch ( ... )

   {

   // handler for any C++ exception

   cout << "A C++ exception was thrown.";

   return 1;

   }

}


try

See also	Example	Keywords

Category

Statements, C++-Specific Keywords

Syntax

try compound-statement handler-list

Description

The try keyword is supported only in C++ programs. Use __try in C programs. C++ also allows __try.

A block of code in which an exception can occur must be prefixed by the keyword try. Following the try keyword is a block of code enclosed by braces. This indicates that the program is prepared to test for the existence of exceptions. If an exception occurs, the program flow is interrupted. The sequence of steps taken is as follows:

The program searches for a matching handler

If a handler is found, the stack is unwound to that point

Program control is tranferred to the handler

If no handler is found, the program will call the terminate function. If no exceptions are thrown, the program executes in the normal fashion.


typedef

Example	Keywords

Category

Storage class specifiers

Syntax

typedef <type definition> <identifier> ;

Description

Use the typedef keyword to assign the symbol name <identifier> to the data type definition <type definition>.


Examples

typedef unsigned char byte;

typedef char str40[41];

typedef struct {

     double re, im;

   } complex;


typename

Category

C++-Specific Keywords

Syntax 1

typename identifier

Syntax 2

template <  typename identifier  > class identifier

Description

Use the syntax 1 to reference a type that you have not yet defined. See example 1.

Use syntax 2 in place of the class keyword in a template declaration. See  example 2.


typename Example 2

/* This example shows how the typename keyword can be used to replace the class keyword in a template declaration. */

#include <iostream.h>

template <typename T1, typename T2> T2 convert (T1 t1)

                             // use typename instead of class.

{ return (T2)t1; }

template <typename X, class Y> bool isequal (X x, Y y)

                             // mix typename and class.

{ if (x==y)return 1; return 0; }


typename Example 1

/* This example uses the typename keyword to declare variables as type T::A, which has not yet been defined. */

template <class T>

void f() {

  typedef typename T::A TA; 	// declare TA as type T::A

  TA a5;	          	// declare a5 as type TA

  typename T::A a6;         	// declare a6 as type T::A

  TA * pta6;             	// declare pta6 as pointer to type TA

}


typeid

See also	Example	Keywords

Category

Operators, C++-Specific Keywords

Syntax

typeid( expression )

typeid( type-name )

Description

You can use typeid to get run-time identification of types and expressions. A call to typeid returns a reference to an object of type const type_info. The returned object represents the type of the typeid operand.

If the typeid operand is a dereferenced pointer or a reference to a polymorphic type, typeid returns the dynamic type of the actual object pointed or referred to. If the operand is non-polymorphic, typeid returns an object that represents the static type.

You can use the typeid operator with fundamental data types as well as user-defined types.

When the typeid operand is a Delphi class object/reference, typeid returns the static rather than runtime type. Click here to see an example.

If the typeid operand is a dereferenced NULL pointer, the Bad_typeid exception is thrown.


Delphi typeid example

// For Delphi objects, typeid returns the static type, not the runtime type

static const char *TypeIdName(TObject *c) {

   return typeid(*c).name();

}

//  The button’s caption is set to TObject, not TButton.

void __fastcall TForm1::Button1Click(TObject *Sender) {

   Button1->Caption = TypeIdName(Button1);

}


typeid example
// typeid example

// HOW TO USE operator typeid, Type_info::before(), AND Type_info::name()

#include <iostream.h>

#include <typeinfo.h>

class A { };

class B : A { };

void main() {

   char C;

   float X;

   // USE THE type_info::operator==()TO MAKE COMPARISON

   if (typeid( C ) == typeid( X ))

      cout << "C and X are the same type." << endl;

   else cout << "C and X are NOT the same type." << endl;

   // USE true AND false LITERALS TO MAKE COMPARISON

   cout << typeid(int).name();

   cout << " before " << typeid(double).name() << ": " <<

        (typeid(int).before(typeid(double)) ? true : false) << endl;

   cout << typeid(double).name();

   cout << " before " << typeid(int).name() << ": " <<

        (typeid(double).before(typeid(int)) ? true : false) << endl;

   cout << typeid(A).name();

   cout << " before " << typeid(B).name() << ": " <<

        (typeid(A).before(typeid(B)) ? true : false) << endl;

   }

Program Output

C and X are NOT the same type.

int before double: 0

double before int: 1

A before B: 1


union

See also	Example	Keywords

Category

Type specifiers

Syntax

union [<union type name>] {

  <type> <variable names> ;

  ...

} [<union variables>] ;

Description

Use unions to define variables that share storage space.

The compiler allocates enough storage in a_number to accommodate the largest element in the union.

Unlike a struct, the variables a_number.i and a_number.l occupy the same location in memory. Thus, writing into one overwrites the other.

Use the record selector (.) to access elements of a union .


Example

union int_or_long {

  int     i;

  long    l;

} a_number;


unsigned

See also	Example	Keywords

Category

Type specifiers

Syntax

unsigned <type> <variable> ;

Description

Use the unsigned type modifier when variable values will always be positive. The unsigned modifer can be applied to base types int, char, long, short, and __int64.

When the base type is omitted from a declaration, int is assumed.


Examples

unsigned int       i;

unsigned           i;    /* same as "unsigned int i;"    */

unsigned long int  l;    /* int OK, not needed           */

unsigned char      ch;   /* unsigned is default for char */


virtual

Keywords

Category

C++-Specific Keywords

Syntax

virtual class-name

virtual function-name

Description

Use the virtual keyword to allow derived classes to provide different versions of a base class function. Once you declare a function as virtual, you can redefine it in any derived class, even if the number and type of arguments are the same.

The redefined function overrides the base class function.


void

Example	Keywords

Category

Special types

Syntax

void identifier

Description

void is a special type indicating the absence of any value. Use the void keyword as a function return type if the function does not return a value.

void hello(char *name)

{

  printf("Hello, %s.",name);

}

Use void as a function heading if the function does not take any parameters.

int init(void)

{

  return 1;

}

Void Pointers

Generic pointers can also be declared as void, meaning that they can point to any type.

void pointers cannot be dereferenced without explicit casting because the compiler cannot determine the size of the pointer object.


Example

int x;

float r;

void *p = &x;          /* p points to x */

int main (void)

{

  *(int *) p = 2;

  p = &r;              /* p points to r */

  *(float *)p = 1.1;

}


volatile

See also	Keywords

Category

Modifiers

Syntax

volatile <data definition> ;

Description

Use the volatile modifier to indicate that a variable can be changed by a background routine, an interrupt routine, or an I/O port. Declaring an object to be volatile warns the compiler not to make assumptions concerning the value of the object while evaluating expressions in which it occurs because the value could change at any moment. It also prevents the compiler from making the variable a register variable

volatile int ticks;

void timer( ) {

   ticks++;

}

void wait (int interval) {

   ticks = 0;

   while (ticks < interval);  // Do nothing

}

The routines in this example (assuming timer has been properly associated with a hardware clock interrupt) implement a timed wait of ticks specified by the argument interval. A highly optimizing compiler might not load the value of ticks inside the test of the while loop since the loop doesn’t change the value of ticks.

Note:	C++ extends volatile to include classes and member functions. If you’ve declared a volatile object, you can use only its volatile member functions.


while

See also	Example	Keywords

Category

Statements

Syntax

while ( <condition> ) <statement>

Description

Use the while keyword to conditionally iterate a statement.

<statement> executes repeatedly until the value of <condition> is false.

The test takes place before <statement> executes. Thus, if <condition> evaluates to false on the first pass, the loop does not execute.


Example

while (*p == ' ') p++;


wchar_t

Category

C++-Specific Keywords, Type specifiers

Syntax

wchar_t <identifier>;

Description

In C++ programs, wchar_t is a fundamental data type that can represent distinct codes for any element of the largest extended character set in any of the supported locales. A wchar_t type is the same size, signedness, and alignment requirement as an int type.


What is a dynamic link library?
What is a dynamic-link library?

Dynamic-link libraries (DLLs) provide a way to modularize applications so that functionality can be updated and reused more easily. They also help reduce memory overhead when several applications use the same functionality at the same time, because although each application gets its own copy of the data, they can share the code.

In Windows, DLLs are modules that contain functions and data. A DLL is loaded at runtime by its calling modules (.EXE or DLL). When a DLL is loaded, it is mapped into the address space of the calling process.

DLLs can define two kinds of functions: exported and internal. The exported functions can be called by other modules. Internal functions can only be called from within the DLL where they are defined.

The creation and use of DLLs is described in detail in the Microsoft® Win32 SDK Reference.


Using DLLs in C++Builder

A Windows DLL can be used by a C++Builder application just as it would be by any C++ application.

To statically load a DLL when your C++Builder application is loaded, link the import library file for that DLL into your C++Builder application at link time. To add an import library to a C++Builder application, open the make file (.BPR) for the application and add the import library name to the library file list assigned to the ALLLIB variable. If necessary, add the path of the import library to the path(s) listed for the -L option of LFLAGS (linker options) variable.

The exported functions of that DLL then become available for use by your application. Prototype the DLL functions your application uses with __declspec(dllimport) modifier:

__declspec(dllimport) return_type imported_function_name(parameters);

To dynamically load a DLL during the run of a C++Builder application use the Windows API function LoadLibrary() to load the DLL, then use the API function GetProcAddress() to obtain pointers to the individual functions you wish to use.

Additional information on using DLLs can be found in the Microsoft® Win32 SDK Reference.


Creating DLLs in C++Builder

Creating DLLs in C++Builder is the same as in standard C++. Exported functions in the code should be identified with the __declspec (dllexport) modifier as they would be in Borland C++ or Microsoft Visual C++. For example, the following code is legal in C++Builder and other Windows C++ compilers:

// MyDLL.cpp

double dblValue(double);

double halfValue(double);

extern “C” __declspec(dllexport) double changeValue(double, bool);

double dblValue(double value)

{

return value * value;

};

double halfValue(double value)

{

return value / 2.0;

}

double changeValue(double value, bool whichOp)

{

return whichOp ? dblValue(value) : halfValue(value);

}

In the code above, the function changeValue is exported, and therefore made available to calling applications. The functions dblValue and halfValue are internal, and cannot be called from outside of the DLL.

In the C++Builder IDE, a new DLL project can be created by selecting File | New and selecting the DLL icon from the New tab. A new edit window opens and the project options are set to build a DLL, rather than an EXE. Notice that by default VCL.H is included in the new DLL source. If your DLL does not use any VCL components, you can remove this line.

Additional information on creating DLLs can be found in the Microsoft® Win32 SDK Reference.


Creating DLLs containing VCL components

One of the strengths of DLLs is that a DLL created with one development tool can often be used by application written using a different development tool. When your DLL contains VCL components (such as forms) that are to be utilized by the calling application, you need to provide exported interface routines that use standard calling conventions, avoid C++ name mangling, and do not require the calling application to support the VCL library in order to work. To create VCL components that can be exported, use runtime packages.

For example, suppose we want to create a DLL to display the following simple dialog box:

The code for the dialog box DLL is as follows:

// DLLMAIN.H

//---------------------------------------------------------------------

#ifndef dllMainH

#define dllMainH

//---------------------------------------------------------------------

#include <vcl\Classes.hpp>

#include <vcl\Controls.hpp>

#include <vcl\StdCtrls.hpp>

#include <vcl\Forms.hpp>

//---------------------------------------------------------------------

class TYesNoDialog : public TForm

{

__published:    // IDE-managed Components

    TLabel *LabelText;

    TButton *YesButton;

    TButton *NoButton;

    void __fastcall YesButtonClick(TObject *Sender);

    void __fastcall NoButtonClick(TObject *Sender);

private:        // User declarations

    bool returnValue;

public:         // User declarations

    virtual __fastcall TYesNoDialog(TComponent* Owner);

    bool __fastcall GetReturnValue();

};

// exported interface function

extern "C" __declspec(dllexport) bool InvokeYesNoDialog();

//---------------------------------------------------------------------

  extern TYesNoDialog *YesNoDialog;

//---------------------------------------------------------------------

#endif

// DLLMAIN.CPP

//---------------------------------------------------------------------

#include <vcl\vcl.h>

#pragma hdrstop

#include "dllMain.h"

//---------------------------------------------------------------------

#pragma resource "*.dfm"

TYesNoDialog *YesNoDialog;

//---------------------------------------------------------------------

__fastcall TYesNoDialog::TYesNoDialog(TComponent* Owner)

  : TForm(Owner)

{

   returnValue = false;

}

//---------------------------------------------------------------------

void __fastcall TYesNoDialog::YesButtonClick(TObject *Sender)

{

    returnValue = true;

    Close();

}

//---------------------------------------------------------------------

void __fastcall TYesNoDialog::NoButtonClick(TObject *Sender)

{

    returnValue = false;

    Close();

}

//---------------------------------------------------------------------

bool __fastcall TYesNoDialog::GetReturnValue()

{

    return returnValue;

}

//---------------------------------------------------------------------

// exported standard C++ interface function that calls into VCL

bool InvokeYesNoDialog()

{

    bool returnValue;

TYesNoDialog *YesNoDialog = new TYesNoDialog(NULL);

    YesNoDialog->ShowModal();

returnValue = YesNoDialog->GetReturnValue();

delete YesNoDialog;

    return returnValue;

}

//---------------------------------------------------------------------

The code in this example, displays the dialog and stores the value true in the private data member returnValue if the “Yes” button is pressed. Otherwise, returnValue is false. The public GetReturnValue() function retrieves the current value of returnValue.

To invoke the dialog and determine which button was pressed, the calling application calls the exported function InvokeYesNoDialog(). This function is declared in DLLMAIN.H as an exported function using C linkage (to avoid C++ name mangling) and the standard C calling convention. The function is defined in DLLMAIN.CPP.

By using a standard C function as the interface into the DLL, any calling application, whether or not it was created with C++Builder, can use the DLL. The VCL functionality required to support the dialog is linked into the DLL itself and the calling application does not need to know anything about it.

Note that when creating a DLL that uses the VCL, the required VCL components are linked into the DLL resulting in a certain amount of overhead. The impact of this overhead on the overall size of the application can be minimized by combining several components into one DLL which only needs one copy of the VCL support components.


Linking DLLs

You can set the linker options for your DLL on the Linker page of the Project Options dialog. The default checkbox on this page also creates an import library for your DLL. If compiling from the command line, invoke the linker, ILINK32.EXE, with the -Tpd switch. For example,:

ilink32 /c /aa /Tpd c0d32.obj mydll.obj, mydll.dll, mdll.map, import32.lib cw32mt.lib

If you need an import library, use the -Gi switch also, to generate an import library.

You can optionally create an import library with the command line utility IMPLIB.EXE. For example,

implib mydll.lib mydll.dll

For more information about the different options for linking DLLs and using them with other modules that are statically or dynamically linked to the runtime library, see Linking issues.


Example of base class referencing

template <class T> class B

{

  // class declarations

};

template <class T> class D : public B<T>

{

   // class declarations

};

template <class T> void func(B <T> *b)

{

   // function body

}

// This is illegal under ANSI C++: unresolved func( int )

// However, Borland C++ calls func( B<int> * ).

func( new D<int> );


Example of trivial conversions

template <class T> void func(const T)

{

   .

   .

   .

};

func(0);  // This is illegal under ANSI C++: unresolved func(int).

// However, Borland C++  allows func(const int) to be called.


Example of explicit template function

template<class T> T max(T a, T b) {

        return  (a > b) ? a : b;

};

// Declare explicit template function

int     max(int,int);

void    f(int i, char c)

{

        max(i, i);              // calls max(int ,int )

        max(c, c);              // calls max(char,char)

        max(i, c);              // calls max(int,int)

        max(c, i);              // calls max(int,int)

}


Class template definition

// An example for defining a template class.

template <class T> class Vector

{

   T *data;

   int size;

public:

   Vector(int);

   ~Vector( ) { delete[ ] data; }

   T& operator[ ] (int i) { return data[i]; }

};

// Note the syntax for out-of-line definitions.

template <class T> Vector<T>::Vector(int n)

{

   data = new T[n];

   size = n;

};

int main()

{

   Vector<int> x(5);   // Generate a vector to store five integers

   for (int i = 0; i < 5; ++i)

      x[i] = i;              //  Initialize the vector.

   return o;

}


Export/Import Template Declarations
Exportable/Importable Template Declarations

// In file EXPORTER.H

#include<iostream.h>

# if defined (BUILD_DLL_EXPORTS)

#     define DECLSPEC __export

# elif defined (USING_DLL_IMPORTS)

#     define DECLSPEC __import

# endif

/////////////////////////////////////////////////

// Receive CLASS DEFINITIONS

template <class T> class Receive

{

  T value;

public:

  Receive(const T val) : value(val){}

   T display();

};

template<class T> T Receive<T>::display()

{

  return value;

}

// TEMPLATE FUNCTION DEFINITION

template <class T>

T another_min(T a, T b) { return a < b ? a : b;}

#if (defined (BUILD_DLL_EXPORTS) ||  defined(USING_DLL_IMPORTS) )

////// INSTANTIATED TEMPLATE CLASSES /////

template class DECLSPEC Receive<double>;

template class DECLSPEC Receive<int>;

template class DECLSPEC Receive<char>;

////// INSTANTIATED TEMPLATE FUNCTIONS /////

template int DECLSPEC another_min<int>(int, int);

template double DECLSPEC another_min<double>(double, double);

#endif


Compiling Exportable Templates

// In file DLL_SRC.CPP.

// GENERATE CODE FOR EXPORTABLE CLASSES AND FUNCTIONS.

// TO COMPILE THIS FILE, USE BCC32 -tWD -DBUILD_DLL_EXPORTS DLL_SRC.CPP

#define STRICT

#include <windows.h>

#include "exporter.h"

BOOL WINAPI DllEntryPoint(HINSTANCE hinstdll,

                          DWORD fdwReason, LPVOID lpvReserved)

{

  return 1;

}


Using Import Templates

Program Output

// Before you compile this file you need to create the dynamic link library.

// You can use the command IMPLIB DLL_SRC.LIB DLL_SRC.DLL

// TO COMPILE THIS FILE, USE BCC32 -DUSING_DLL_IMPORTS MAIN DLL_SRC.LIB

#include <iostream.h>

#include "exporter.h"

int main () {

   int small = 5;

   int big = 10;

   double smalld = 1.2;

   double bigd = 12.3;

   // No new code is generated for these objects.

   Receive <double> Test_d(0.01);

   Receive <int> Test_i(5);

  // Generate code in MAIN.OBJ for this object.

  Receive <float> Test_f(3.14);

   cout << "Test_d.display() = " <<  Test_d.display() << endl;

   cout << "Test_i.display() = " <<  Test_i.display() << endl;

   cout << "min(5, 10): " << another_min(small, big) << endl;

   cout << "min(12.3, 1.2): " << another_min(bigd, smalld)<<endl;

   cout << "Test_f.display() = " <<  Test_f.display() << endl;

   return 0;

}


Program Output

Test_d.display() = 0.01

Test_i.display() = 5

min(5, 10): 5

min(12.3, 1.2): 1.2

Test_f.display() = 3.14


// Example of the new and delete Operators

// ALLOCATE A TWO-DIMENSIONAL SPACE, INITIALIZE, AND DELETE IT.

#include <exception>

#include <iostream.h>

void display(long double **);

void de_allocate(long double **);

int m = 3;                               // THE NUMBER OF ROWS.

int n = 5;                               // THE NUMBER OF COLUMNS.

int main(void) {

   long double **data;

   try {                                 // TEST FOR EXCEPTIONS.

      data = new long double*[m];        // STEP 1: SET UP THE ROWS.

      for (int j = 0; j < m; j++)

          data[j] = new long double[n];  // STEP 2: SET UP THE COLUMNS

      }

   catch (std::bad_alloc) {  // ENTER THIS BLOCK ONLY IF bad_alloc IS THROWN.

      // YOU COULD REQUEST OTHER ACTIONS BEFORE TERMINATING

      cout << "Could not allocate. Bye ...";

      exit(-1);

      }

   for (int i = 0; i < m; i++)

      for (int j = 0; j < n; j++)

          data[i][j] = i + j;            // ARBITRARY INITIALIZATION

   display(data);

   de_allocate(data);

   return 0;

   }

void display(long double **data) {

   for (int i = 0; i < m; i++) {

        for (int j = 0; j < n; j++)

             cout << data[i][j] << " ";

       cout << "\n" << endl;

       }

   }

void de_allocate(long double **data) {

   for (int i = 0; i < m;  i++)

       delete[] data[i];                 // STEP 1: DELETE THE COLUMNS

   delete[] data;                        // STEP 2: DELETE THE ROWS

   }


operator new placement syntax example

// An example of the placement syntax for operator new()

#include <iostream.h>

class Alpha {

  union {

    char  ch;

    char  buf[10];

    };

public:

   Alpha(char c = '\0') : ch(c) {

      cout << "character constructor" << endl;

      }

   Alpha(char *s) {

      cout << "string constructor" << endl;

      strcpy(buf,s);

      }

   ~Alpha( ) { cout << "Alpha::~Alpha() " << endl; }

   void * operator new(size_t, void * buf) {

      return buf;

      }

};

void main() {

   char *str = new char[sizeof(Alpha)];

   // Place 'X' at start of str.

   Alpha* ptr = new(str) Alpha('X');

   cout << "str[0] = " << str[0] << endl;

   // Explicit call of the destructor

   ptr -> Alpha::~Alpha();

   // Place a string in str buffer.

   ptr = new(str) Alpha("my string");

   cout << "\n str = " << str << endl;

   // Explicit call of the destructor

   ptr -> Alpha::~Alpha();

   delete[] str;

   }

Output

character constructor

str[0] = X

Alpha::~Alpha()

string constructor

 str = my string

Alpha::~Alpha()


Example

// The MakeStr function takes an "array of const"

AnsiString MakeStr(const TVarRec* args, int argHigh)

{

  String tmp;

  for (int i = 0; i <= argHigh; i++)

  switch (args[i].VType)

  {

    case vtInteger:

      tmp += ::IntToStr(args[i].VInteger);

      break;

    case vtBoolean:

      tmp += args[i].VBoolean? "T": "F";

      break;

    case vtChar:

      tmp += String(&args[i].VChar, 1);

      break;

    case vtExtended:

      tmp +=  ::FloatToStr(*args[i].VExtended);

      break;

    case vtString:

      tmp += *args[i].VString;

      break;

    case vtPChar:

      tmp += String(args[i].VPChar);

      break;

    case vtObject:

      tmp += "-TObject-"; //classname not available args[i].VObject->ClassName();

      break;

    case vtClass:

      tmp += "-TClass-"; //classname not available args[i].VClass->ClassName();

      break;

    case vtAnsiString:

      tmp += String(reinterpret_cast<char*>(args[i].VAnsiString));

      break;

    case vtCurrency:

      tmp += ::CurrToStr(*args[i].VCurrency);

      break;

    case vtVariant:

      tmp += *args[i].VVariant;

      break;

    default:

      tmp += "-Other-";

  };

  return tmp;

}

// MakeStr is called with OPENARRAY(TVarRec, (...))

  ::MessageBox(0,

    MakeStr(OPENARRAY(TVarRec,(1, true, 'a', (long double)3.14159,

    ShortString("shstr"), "hello", *this, __classid(TForm1), String("str"),

    Currency(1.23), Variant("var")))).c_str(), PChar("MakeStr"), MB_OK);

// The resulting message box contains:

//  1Ta3.14159shstrhello-TObject--TClass-str1.23var


Variant example

#include <vcl.h>

#pragma hdrstop

#include <iostream.h>

#include <oleauto.hpp>

#include <math.h>

//--------------------------------------------------------------------

void TestConstructors();

void TestAssignments();

void TestTypeChanging();

void TestOperators();

void TestArrays();

void TestOle();

//--------------------------------------------------------------------

main()

{

    TestConstructors();

    TestAssignments();

    TestTypeChanging();

    TestOperators();

    TestArrays();

    TestOle();

    return 0;

}

//--------------------------------------------------------------------

void CheckType(const Variant& v, Word type)

{

  if (v.VType == type)

    cout << "Type Check OK: ";

  else  cout << "Type Check ERROR: ";

  cout <<   "type: " << v.VType;

  cout << ", expected: " << type << endl;

}

//--------------------------------------------------------------------

void Compare(Variant &lhs, Variant &rhs)

{

  if (lhs == rhs)

    cout << "Compare OK: ";

  else

    cout << "Compare ERROR: ";

  cout <<   "lhs type: " << lhs.VType;

  cout << ", rhs type: " << rhs.VType;

  cout << ", lhs val: "  << String(lhs).c_str();

  cout << ", rhs val: "  << String(rhs).c_str() << endl;

}

//--------------------------------------------------------------------

void TestConstructors()

{

  static short smallint = 3;

  static int integer = 4;

  static float flt = 5;

  static double dbl = 6;

  static Currency currency = 7;

  static TDateTime date = String("05/11/95");

  static WordBool boolean = true;

  static Byte byte = 9;

  static wchar_t* oleStr = SysAllocString(L"Hey, welcome to the world of variant and OLE");

  Variant vEmpty;

  //can't actually construct a null

  Variant vNull;

  vNull.ChangeType(varNull);

  // by value

  Variant vSmallint(short(3));

  Variant vInteger(4);

  Variant vSingle(float(5));

  Variant vDouble(double(6));

  Variant vCurrency(Currency(7));

  Variant vDate(TDateTime(String("05/11/95")));

  Variant vBoolean(true);

  Variant vByte((Byte)9);

  Variant vString(String("This is an ANSI string, buddy!"));

  Variant vOleStr(L"Hey, welcome to the world of Variants & OLE Automation");

  Variant vDispatch(Variant::CreateObject("Word.Basic"));

  Variant vUnknown(Variant::CreateObject("Word.Basic").AsType(varUnknown));

  // by reference

  Variant vrSmallint = &smallint;

  Variant vrInteger = &integer;

  Variant vrSingle = &flt;

  Variant vrDouble = &dbl;

  Variant vrCurrency = &currency;

  Variant vrDate = &date;

  Variant vrBoolean = &boolean;

  Variant vrByte = &byte;

  Variant vrOleStr = &oleStr;

  cout << endl << "TestConstructors output:" << endl;

  CheckType(vEmpty, varEmpty);

  CheckType(vNull, varNull);

  cout << endl << "TestConstructors(byval) output:" << endl;

  CheckType(vSmallint, varSmallint);

  CheckType(vInteger, varInteger);

  CheckType(vSingle, varSingle);

  CheckType(vDouble, varDouble);

  CheckType(vCurrency, varCurrency);

  CheckType(vDate, varDate);

  CheckType(vBoolean, varBoolean);

  CheckType(vByte, varByte);

  CheckType(vString, varString);

  CheckType(vOleStr, varOleStr);

  CheckType(vDispatch, varDispatch);

  CheckType(vUnknown, varUnknown);

  cout << endl << "TestConstructors(byref) output:" << endl;

  CheckType(vrSmallint, varSmallint | varByRef);

  CheckType(vrInteger, varInteger | varByRef);

  CheckType(vrSingle, varSingle | varByRef);

  CheckType(vrDouble, varDouble | varByRef);

  CheckType(vrCurrency, varCurrency | varByRef);

  CheckType(vrDate, varDate | varByRef);

  CheckType(vrBoolean, varBoolean | varByRef);

  CheckType(vrByte, varByte | varByRef);

  CheckType(vrOleStr, varOleStr | varByRef);

  SysFreeString(oleStr);

}

//--------------------------------------------------------------------

void TestAssignments()

{

  Variant vEmpty, vNull;

  //by val

  Variant vSmallint, vInteger, vSingle, vDouble, vCurrency, vDate;

  Variant vOleStr, vDispatch, vBoolean, vByte, vString, vUnknown;

  //by ref

  Variant vrSmallint, vrInteger, vrSingle, vrDouble, vrCurrency, vrDate;

  Variant vrOleStr, vrDispatch, vrBoolean, vrByte, vrString, vrUnknown;

  static short smallint = 3;

  static int integer = 4;

  static float flt = 5;

  static double dbl = 6;

  static Currency currency = 7;

  static TDateTime date = String("05/11/95");

  static WordBool boolean = true;

  static Byte byte = 9;

  static wchar_t* oleStr = SysAllocString(L"Hey, welcome to the world of variant and OLE");

  vEmpty = Variant();

  vNull = Variant().ChangeType(varNull);

  //by value

  vSmallint = (short)3;

  vInteger = 4;

  vSingle = (float)5;

  vDouble = (double)6;

  vCurrency = Currency(7);

  vDate = (TDateTime) StrToDate(String("03/27/77"));

  vBoolean = true;

  vByte = (Byte)9;

  vString = "This is a Ansi string";

  vOleStr = L"This is an OLE string";

  vDispatch = Variant::CreateObject("Word.Basic");

  vUnknown = Variant::CreateObject("Word.Basic").AsType(varUnknown);

  // by reference

  vrSmallint = &smallint;

  vrInteger = &integer;

  vrSingle = &flt;

  vrDouble = &dbl;

  vrCurrency = &currency;

  vrDate = &date;

  vrBoolean = &boolean;

  vrByte = &byte;

  vrOleStr = &oleStr;

  cout << endl << "TestAssignments output:" << endl;

  CheckType(vEmpty, varEmpty);

  cout << endl << "TestAssignments (by val) output:" << endl;

  CheckType(vSmallint, varSmallint);

  CheckType(vInteger, varInteger);

  CheckType(vSingle, varSingle);

  CheckType(vDouble, varDouble);

  CheckType(vCurrency, varCurrency);

  CheckType(vDate, varDate);

  CheckType(vBoolean, varBoolean);

  CheckType(vByte, varByte);

  CheckType(vString, varString);

  CheckType(vOleStr, varOleStr);

  CheckType(vDispatch, varDispatch);

  CheckType(vUnknown, varUnknown);

  cout << endl << "TestAssignments (by ref) output:" << endl;

  CheckType(vrSmallint, varSmallint | varByRef);

  CheckType(vrInteger, varInteger | varByRef);

  CheckType(vrSingle, varSingle | varByRef);

  CheckType(vrDouble, varDouble | varByRef);

  CheckType(vrCurrency, varCurrency | varByRef);

  CheckType(vrDate, varDate | varByRef);

  CheckType(vrBoolean, varBoolean | varByRef);

  CheckType(vrByte, varByte | varByRef);

  CheckType(vrOleStr, varOleStr | varByRef);

  SysFreeString(oleStr);

}

//--------------------------------------------------------------------

void TestTypeChanging()

{

  Variant vSmallint = 3;

  Variant vx, vy;

  cout << endl << "TestTypeChanging output:" << endl;

  vx = vSmallint.AsType(varString);

  CheckType(vx, varString);

  vx.ChangeType(varInteger);

  CheckType(vx, varInteger);

  vy = vx.AsType(varSingle);

  CheckType(vy, varSingle);

  CheckType(vx, varInteger);

  vx.Clear();

  CheckType(vx, varEmpty);

}

//--------------------------------------------------------------------

void TestOperators()

{

  Variant vx, vy;

  cout << endl <<"TestOperators output:" << endl;

  vx = 5;

  vy = vx + 0;

  Compare(vy, vx);

  Compare(vx-0, vx);

  Compare(vx*1, vx);

  Compare(vx/1, vx);

  vx = 5;

  vy = vx + 0;

  Compare(vy, vx);

  Compare(vx-0, vx);

  Compare(vx*1, vx);

  Compare(vx/1, vx);

  vy = vx;

  Compare(vy+=0, vx);

  Compare(vy-=0, vx);

  Compare(vy*=1, vx);

  Compare(vy/=1, vx);

  vx = 5;

  vy = 46;

  vx = 2*vx + (vy-6)/2;

  Compare(vx, 30);

  vx = "hi ";

  vy = "there";

  vx += vy;

  Compare(vx, "hi there");

  //force a variant so we can test variant's operator+

  vx = 1 + 20.0 + Variant(String("300"));

  Compare(vx, 321);

  vx = 15;

  vy = (vx == 15);

  Compare(vy, true);

  vy = (vx < 15);

  Compare(vy, false);

  vy = (vx > 15);

  Compare(vy, false);

  vy = (vx != 15.3);

  Compare(vy, true);

}

//--------------------------------------------------------------------

void TestArrays()

{

  Variant a, b;

  int i, tmp;

  cout << endl <<"TestArrays output:" << endl;

  a = VarArrayCreate(OPENARRAY(int, (0, 9)), varInteger);

  b = VarArrayCreate(OPENARRAY(int, (1, 3, 0, 9)), varInteger);

  // Do it with array lock

  int* ax = (int*) a.ArrayLock();

  for (i=0; i < 10; i++)

    ax[i] = i*i;

  Compare(ax[0], 0);

  Compare(ax[9], 81);

  a.ArrayUnlock();

  //Do it again with Put/GetElement

  for (i=0; i < 10; i++)

  {

    tmp = i*i*i;

    a.PutElement(&tmp, i);

  }

  Compare(a.GetElement(0), 0);

  Compare(a.GetElement(9), 9*9*9);

  // Try a 2-dimensional array

  for (i=0; i < 10; i++)

  {

    b.PutElement(&i, 1, i);

    tmp = sqrt(i);

    b.PutElement(&tmp, 2, i);

    tmp = i*i;

    b.PutElement(&tmp, 3, i);

  }

  Compare(b.GetElement(1,0), 0);

  Compare(b.GetElement(1,9), 9);

  Compare(b.GetElement(2, 0), 0);

  Compare(b.GetElement(2, 9), 3);

  Compare(b.GetElement(3, 0), 0);

  Compare(b.GetElement(3, 9), 81);

}

//--------------------------------------------------------------------

void TestOle()

{

  Variant   wordBasic, res;

  Function  fileNew("FileNew");

  Procedure insert("Insert");

  Function  fileSaveAs("FileSaveAs");

  cout << endl << "TestOle:  check contents of test.txt" << endl;

  wordBasic = Variant::CreateObject("Word.Basic");

  res = wordBasic.Exec(fileNew <<"Normal");

  wordBasic.Exec(insert <<"This is the first line\n");

  wordBasic.Exec(insert.ClearArgs() <<"This is the second line\n");

  res = wordBasic.Exec(fileSaveAs <<"test.txt" <<3);

}