An aggregate type is a type that:
Is an array or class type
Has no constructors (for class types)
Has no nonpublic members (for class types)
Has no base classes (for class types)
Has no virtual functions (for class types)
Initializers for aggregates can be specified as a comma-separated list of values enclosed in curly braces. For example, this code declares an int array of 10 and initializes it:
int rgiArray[10] = { 9, 8, 4, 6, 5, 6, 3, 5, 6, 11 };
The initializers are stored in the array elements in increasing subscript order. Therefore, rgiArray[0] is 9, rgiArray[1] is 8, and so on, until rgiArray[9], which is 11. To initialize a structure, use code such as the following:
struct RCPrompt
{
short nRow;
short nCol;
char *szPrompt;
};
RCPrompt rcContinueYN = { 24, 0, "Continue (Y/N?)" };
Length of Aggregate-Initializer Lists
If an aggregate initializer list is shorter than the array or class type that is being initialized, zeros are stored in the elements for which no initializer is specified. Therefore, the following two declarations are equivalent:
// Explicitly initialize all elements.
int rgiArray[5] = { 3, 2, 0, 0, 0 };
// Allow remaining elements to be zero-initialized.
int rgiArray[5] = { 3, 2 };
While initializer lists can be truncated, as shown above, supplying too many initializers generates an error.
Initializing Aggregates That Contain Aggregates
Some aggregates contain other aggregates—for example, arrays of arrays, arrays of structures, or structures that are composed of other structures. Initializers can be supplied for such constructs by initializing each one in the order it occurs with a brace-enclosed list. For example:
// Declare an array of type RCPrompt.
RCPrompt rgRCPrompt[4] =
{ { 4, 7, "Options Are:" },
{ 6, 7, "1. Main Menu" },
{ 8, 7, "2. Print Menu" },
{ 10, 7, "3. File Menu" } };
Note that rgRCPrompt is initialized with a brace-enclosed list of brace-enclosed lists. The enclosed braces are not syntactically required, but they lend clarity to the declaration. The following example program shows how a two-dimensional array is filled by such an initializer:
#include <iostream.h>
main()
{
int rgI[2][4] = { 1, 2, 3, 4, 5, 6, 7, 8 };
for( int i = 0; i < 2; ++i )
for( int j = 0; j < 4; ++j )
cout << "rgI[" << i << "][" << j << "] = "
<< rgI[i][j] << endl;
return 0;
}
The output from this program is:
rgI[0][0] = 1
rgI[0][1] = 2
rgI[0][2] = 3
rgI[0][3] = 4
rgI[1][0] = 5
rgI[1][1] = 6
rgI[1][2] = 7
rgI[1][3] = 8
Short initialization lists can be used only with explicit subaggregate initializers and enclosed in braces. If rgI had been declared as
int rgI[2][4] = { { 1, 2 }, { 3, 4 } };
the program output would have been
rgI[0][0] = 1
rgI[0][1] = 2
rgI[0][2] = 0
rgI[0][3] = 0
rgI[1][0] = 3
rgI[1][1] = 4
rgI[1][2] = 0
rgI[1][3] = 0
Incomplete types, such as unbounded array types, can be initialized as follows:
char HomeRow[] = { 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l' };
The compiler computes the size of the array from the number of initializers provided.
Incomplete types, such as pointers to class types that are declared but not defined, are declared as follows:
class DefinedElsewhere; // Class definition elsewhere.
class DefinedHere
{
...
friend class DefinedElsewhere;
};
Initializing Using Constructors
Objects of class type are initialized by calling the appropriate constructor for the class. For complete information about initializing class types, see “Explicit Initialization” in Chapter 11, on topic .
Objects of union type are initialized with a single value (if the union does not have a constructor). This is done in one of two ways:
Initialize the union with another object of the same union type. For example:
struct Point
{
unsigned x;
unsigned y;
};
union PtLong
{
long l;
Point pt;
};
...
PtLong ptOrigin;
PtLong ptCurrent = ptOrigin;
In the preceding code, ptCurrent is initialized with the value of ptOrigin—an object of the same type.
Initialize the union with a brace-enclosed initializer for the first member. For example:
PtLong ptCurrent = { 0x0a000aL };