13.4 Introduction to Constructors and Destructors

I l @ ve RuBoard

This stack class has one minor inconvenience. The programmer must call the init member function before using the stack. However, programmers are terribly forgetful, and sooner or later someone is going to forget to initialize the stack. Wouldn't it be nice if C++ had an automatic way of initializing the stack?

It does. Actually C++ will automatically call a number of member functions. The first you are concerned about is called when stack is created. In C++ language this is referred to as "creating an instance of the class stack ."

The function C++ calls to create a instance of the class is called the constructor and has the same name as the class. For example, the constructor for the stack class is named stack ( also known as stack::stack outside the class body).

A variable, or instance of a class, is created when it is defined. (It can also be created by the new operator, as described in Chapter 20.)

You want to have this stack initialized automatically, so you remove the init function and replace it with the constructor, stack::stack:

 class stack {         // ...     public:         // Initialize the stack         stack(  );         // ... }; inline stack::stack(  ) {     count = 0;  // Zero the stack } 

You may have noticed that the return type void has been omitted in the constructor declaration. Constructors can never return a value, so the void is not needed. In fact, the compiler will complain if it's present.

Since the constructor is called automatically, the program is now simpler. Instead of writing:

 int main(  ) {     stack a_stack;      // Stack we want to use     a_stack.init(  ); 

you can just write:

 int main(  ) {     stack a_stack;      // Stack we want to use     // Use the stack 

Also, since you no longer have to count on the programmer putting in the init call, the program is more reliable.

13.4.1 Destructors

The constructor is automatically called when a variable is created. The destructor is automatically called when a variable is destroyed . This occurs when a variable goes out of scope or when a pointer variable is deleted. (The delete operator is defined in Chapter 20.)

The special name for a destructor is the class name with a tilde (~) in front of it. So, for the stack class, the destructor would be named ~stack .

Suppose you make the rule that the stack should be empty when the programmer is finished with it. In other words, for every push you do, a pop must be done. If this doesn't happen, it's an error and you should warn the user .

All you have to do is create a destructor for the stack that checks for an empty stack and issues a warning if the stack is not empty. The destructor looks like this:

 inline stack::~stack(  ) {     if (count != 0)         std::cerr << "Error: Destroying a nonempty stack\n"; } 

13.4.2 Parameterized Constructors

The constructor for a class can take parameters. Suppose you want to define a class that holds a person's name and phone number. The data members for this class would look like this:

 class person {     public:         std::string name;      // Name of the person         std::string phone;     // Person's phone number 

You want the constructor for this class to automatically initialize both the name and the phone number:

 public:         person(const std::string i_name, const std::string i_phone);     // ... rest of class }; person::person(const std::string i_name, const std::string i_phone) {     name = i_name;     phone = i_phone; } 

Now you are ready to use the class. When you declare variables of this class, you must put two parameters in the declaration. For example:

 int main(  ) {     person sam("Sam Jones", "555-1234"); 

Like other functions, constructors can be overloaded. Using the person example, you can take care of the case where you have a person with no phone by creating a constructor that takes a name as its only parameter:

 class person {     // ... rest of the class     public:         person(const std::string i_name); }; person::person(const std::string i_name) {     name = i_name;     phone = "No Phone"; } 

In this case, you have two constructors, one that takes one parameter and one that takes two parameters. You haven't defined a constructor that takes zero parameters, so you can't declare a variable of type person without specifying at least one parameter. In other words:

 person unnamed_source;     // Illegal 

will generate an error message.

13.4.3 Parameterized Destructors

There is no such thing as a parameterized destructor. Destructors take no parameters and supply no return value. All they do is destroy the variable. So there is one and only one destructor for a class.

13.4.4 Copy Constructor

The copy constructor is a special constructor that is used to make an exact copy of a class. For example, a copy constructor for the stack class would look like this:

 stack::stack(const stack& old_stack) {     int i;     // Index used to copy the data     for (i = 0; i < old_stack.count; ++i) {         data[i] = old_stack.data[i];     }     count = old_stack.count; } 

Let's examine this function in more detail. The declaration:

 stack::stack(const stack& old_stack) 

identifies this as a copy constructor. The single parameter ( const stack& old_stack ) identifies this particular constructor as the copy constructor. This function is expected to turn the current instance of the class into an exact copy of the parameter.

The code:

 for (i = 0; i < old_stack.count; ++i) {     data[i] = old_stack.data[i]; } count = old_stack.count; 

takes all the data from the old stack and puts it into the new stack.

The copy constructor can be invoked explicitly, as illustrated in the following example:

 stack a_stack;      // A simple stack a_stack.push(1);    // Put a couple of elements on the stack a_stack.push(2); stack b_stack(a_stack);  // Create a copy of the stack 

On the face of it, the copy constructor doesn't seem that important. But if you remember, back in Chapter 9, I discussed the various ways C++ can pass parameters to a function. One of these was call by value. That's where a copy of the parameter is made and passed to the function.

When a stack or any other class is passed as a call- by-value parameter, a copy is made of that class using the copy constructor.

In the following code, we've added some commentary to show you the functions that C++ will automatically call behind your back:

figs/c++2_13p203.gif

As you can see, C++ does a lot of work behind the scenes. It starts when a_stack is declared. C++ calls the default constructor to create a_stack .

The variable a_stack is used, and then passed to the function use_stack . Since a_stack is passed by value, a copy must be made of the stack using the copy constructor local_stack.stack(a_stack).

The function then adds a few items to local_stack . Note that this is a copy of a_stack, so anything you do to local_stack does not affect a_stack. At the end of the function, local_stack contains four items ”1, 2, 9, 10 ”and a_stack contains two items: 1 and 2.

Finally after the function call, the program prints out the top element of a_stack, which is 2.

I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

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