7.2 ARE THE DEFINED VARIABLES IN C INITIALIZED BY DEFAULT?


7.2 ARE THE DEFINED VARIABLES IN C++ INITIALIZED BY DEFAULT?

Let's say a declaration defines a variable without an initializer. Now the question is, Will the compiler give such a variable a default initialization? The answer to this question is again different for C++ and Java. In C++, only the following kinds of variables are default initialized:

For Primitive Types: Only the global variables of the primitive types are default initialized.

For Class Types: Both local and global variables that are the names of class-type objects are default initialized provided the class has a no-arg constructor.

Table 7.1 summarizes the manner in which the global variables of the primitive types and all variables of class types are default initialized to zeros of the appropriate kind.

Table 7.1

Type

Initial Value

bool

false

char

‘/0'

all integer types

0

all floating-point types

0.0

class type

depends on the no-arg constructor

The following program is a small demonstration of the default initialization of a class type object. The program defines a class User in line (A) and supplies the class with a no-arg constructor in line (B).

 
/ /DefaultInit.cc #include <iostream> #include <string> using namespace std; class User { //(A) public: string name; int age; User() { name = "John Doe"; age = 25; } //(B) }; int main() { //object u defined and initialized : User u; //(C) cout << u.name<< " " << u.age << endl; // John Doe 25 //object *p defined and initialized: User* p = new User(); //(D) cout << p->name << " " <<p->age << endl; // John Doe 25 return 0; }

The following declaration in line (C) of the program

     User u; 

not only defines the object u, it also default initializes the object according to the code in the no-arg constructor of line (B), as borne out by the print-out statement that follows line (C). For the other User object in the above program, in line (D), you'd of course expect it to be constructed according to the no-arg constructor since the no-arg constructor is specifically invoked.

Here is a more elaborate example that illustrates that when an object is created through the mechanism of default-initialization, the class-type data members of the object are also default-initialized according to their own no-arg constructors. Line (D) shows the data member chief of the class UserGroup as an object of type User. The class User, defined in line (A), comes with a no-arg constructor in line (B). And the class UserGroup, defined in line (C), comes with its own no-arg constructor in line (F).

 
//DefaultInit2.cc #include <iostream> #include <string> using namespace std; class User { //(A) public: string name; int age; User() { name = "John Doe"; age = 25; } //(B) }; class UserGroup { //(C) public: User chief; //(D) User* p; // pointer to Users in the group //(E) int priority; UserGroup() { p = 0; priority = 10; } //(F) }; int main() { UserGroup ug; //(G) cout << "chief's name: " << ug.chief.name << " " // John Doe << "chief's age: " << ug.chief.age <<" " // 25 << "pointer value: " << ug.p << // 0 <<"priority level: " << ug.priority << endl; // 10 return 0; }

When a UserGroup object ug is constructed and default-initialized in line (G) by the no-arg constructor of UserGroup, the data member chief is default-initialized according to the no-arg constructor of User. This is borne out by the output shown in the commented out line endings. Note particularly that the no-arg constructor of UserGroup makes no mention of the initialization of the data member chief. This data member is nonetheless default-initialized according to User's no-arg constructor.

7.2.1 What Happens When a No-arg Constructor Is Not Supplied?

Our previous discussion states that when a class type variable is declared without an explicit initializer, it is default-initialized according to the code in the no-arg constructor of the class. That raises the important issue of what happens if the programmer has not supplied a no-arg constructor for a class. There are two different situations to consider in this regard:

  1. If the class has not been supplied with any constructors at all, the system will provide the class with a default no-arg constructor. Ideally, this system-supplied default no-arg constructor ought to initialize each data member of the class to a zero of the appropriate kind. But in practice what happens is implementation dependent and cannot be relied upon. It is entirely possible that the system-supplied default no-arg constructor will merely appropriate the memory and not initialize it at all.

  2. The class has been provided with other constructors, but not a no-arg constructor. In this case, a no-arg constructor simply does not exist. As a result, the compiler will consider illegal a declaration without an explicit initializer.

To illustrate the first case, we have commented out in line (F) below the no-arg constructor for the UserGroup class. The rest of the program is the same as before. Now this class will possess no programmer-supplied constructors at all. The system will therefore provide the class with a default no-arg constructor.

 
//DefaulItnit3.cc #include <iostream> #include <string> using namespace std; class User { //(A) public: string name; int age; User() { name = "John Doe"; age = 25; } //(B) }; class UserGroup { //(C) public: User chief; //(D) User* p; // pointer to Users in the group //(E) int priority; // UserGroup() { p = 0; priority =10; } //(F) }; int main() { UserGroup ug; //(G) cout << "chief's name: " << ug. chief.name <<" " // John Doe << "chief's age: " << ug.chief.age << " " // 25 << "pointer value: " << ug.p << " " // GARBAGE << "priority level: "<< ug.priority << endl; // GARBAGE return 0; }

The output of this program, asshown in the commented-out line endings in main, illustrates that the system-supplied no-arg constructor for UserGroup invokes the programmer-supplied no-arg constructor for the class User. As a result, chief's name and age get initialized to John Doe and 25, respectively. For the other two data members of UserGroup, while the memory is allocated, it is not properly initialized. So we end up with garbage bits for the data members p, and priority.

We said earlier that if a class has been provided with any constructors at all, but not with a no-arg constructor, then there does not exist a no-arg constructor for the class. That condition exists in the UserGroup class in the following program. Line (H)) of the program supplies the class UserGroup with a two-argument constructor; this class, therefore, cannot be provided with a system-supplied default no-arg constructor. As a result, the declaration of the variable ug in line (I) now elicits a compilation error.

 
//DefaultInit4.cc #include <iostream> #include <string> using namespace std; class User { public: string name; int age; User() { name = "John Doe"; age = 25; } }; class UserGroup { public: User chief; User* p; // pointer to Users in the group int priority; UserGroup( User u, User* q, int pr ){} //(H) }; int main() { UserGroup ug; // COMPILATION ERROR //(I) return 0; }

While we are on the subject of no-arg constructors, a class can also be provided with a programmer-defined no-arg constructor through the mechanism of assigning default values to all the parameters of a more regular constructor, as in

     User {         string name;         int age;     public:         User( string nam = "John Doe", int yy = 25 ) {             //(J)            name = nam; age = yy;        }      }; 

Note the default values for the parameters nam and yy in line (J). With this definition of User, we can again construct objects of type User with declarations like

     User uobj;                      // uobj.name = "John Doe" uobj.age = 25     User* p = new User();           // p->name = "John Doe" p->age = 25 

and, using the same constructor, construct objects with specified values for the parameters, as in

     User uobj( "Jane Doe", 28 );   //uobj.name = "Jane Doe" uobj.age = 28 

Note that the following syntax is not acceptable for the invocation of a no-arg constructor:

     User uobj();                     // Wrong for invocation of default constructor 

Using this wrong syntax is not an infrequent error made by beginning C++ programmers. The main reason for this error should be obvious.[1]

7.2.2 Special Consideration for const and Reference Members

As already mentioned, a default no-arg constructor for a class is not supplied by the system if it has any constructors defined for it explicitly. The system also does not supply its own default no-arg constructor if a class contains uninitialized const or reference members.[2] For example,

      class Y {      public:        const int a;        const char ch;      };      Y y;              // ERROR                        //(A) 

Lacking a default no-arg constructor, the compiler refuses to accept the declaration in line (A). When a class has const or reference members, in most cases one has no choice but to also provide a programmer-defined no-arg constructor with special initialization syntax, as in

      class Y {      public:        const int a;        const char ch;        Y() : a(0), ch(0) {}                                //(B)     }; 

where in line (B) we have used what is known as the member initialization syntax for the constructor. In case the reader is wondering why we couldn't do in-class initialization, as in

       class X {          const n = 100;                            // WRONG  }; 

that is prohibited by the language. In-class initialization of the data members of a class, including those that are of type const, is not permitted unless the const members are also static. In other words, the in-class initialization is permitted in C++ for only those data members that are specifically of type static const.[3] As we will see in the next section, Java places no such constraints on in-class initialization of data members.

For another example that includes a reference member r of type int (as was mentioned earlier, object reference in C++ will be explained in detail in the next chapter), consider

     class X {     public:         int& r;         const int n;         int i;         X(int s, int t, int u) : r(s), n(t) { i = u; }       //(C)     };     int main()     {         X xobj(1, 2, 3);         cout << xobj.r << endl;     } 

Note the member initialization syntax in line (C) for the reference member r and the const member n.

[1]Let's consider a class with both a regular constructor with parameters and a programmer-defined no-argument constructor

     User {         string name;         int age;     public:         User() { name = "john doe"; age = 25; }         User( string nam, int yy ) { name = nam; age = yy; }     }; 

An object of type User may now be created by

      User u1( "zahphod", 112 ); 

So it seems natural that if we wanted to invoke the no-arg constructor, we could do so by

      User u2();               // Wrong for invoking no-arg constructor 

Unfortunately, this declaration is construed to be a declaration of a function of name u2 that takes void arguments and whose return type is User.

[2]Object reference in C++ is the subject of the next chapter.

[3]The notion of a static data mamber was introduced briefly in chapter 3 and will be taken up in fuller detail in chapter 11.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net