2012年1月19日 星期四

Constructors and Destructors


Constructors and Destructors

Constructors are special class member functions that are used to create class objects. They execute automatically when an instance of a class is created. Constructors are used to initialize class data members. They are also used to allocate memory for a class. A constructor's name is the same as the class name. 

Destructors are functions that also execute automatically when the object goes out of scope (existence). Destructors, too, have a special name. It is the class name preceded by a ~ (tilde).  Destructors are used to release dynamically allocated memory and to perform other "cleanup" activities.

Example

class xyz
{
  private:
     .
     .
  public:
    xyz();       // constructor prototype
    ~xyz();        // destructor prototype
     .
     .
};

xyz::xyz()                              // constructor definition
{
     .
     .
}

xyz::~xyz()                                 // destructor definition
{
     .
     .
}
     .
     .
     .
int main(void)
{
  xyz thing;       // the construction is called now
     .
     .
     .
  return 0;        // the destructor is called now
}

Constructor/Destructor Notes
  • Constructors and destructors are usually placed in the public part of class definition. 
  • Both the constructor and the destructor have no return type, nor a return statement.
  • Destructors cannot have arguments. Constructors can. They can have several arguments, including default arguments.
  • Constructors are not usually called explicitly. They are called automatically. Destructors are not usually called explicitly.
  • A class may have several constructors. If a class has multiple constructors, the argument list, including default arguments, must be unique. (see box below)
  • Ctor and Dtor are abbreviations for constructor and destructor.
  • Every object must have a constructor. If you do not provide one, the compiler will create one for you. This constructor is a default constructor.  Default constructor also refers to a constructor without arguments.
  • Destructors are automatically called when a class object is deleted.
Overloaded Functions

Overloaded functions are functions with the same name, but different arguments.  The following function prototypes illustrate overloaded functions:

int funk();

int funk(int x);

int funk(double d);

int funk(char*, int);

int funk(xyz&, abc&);

void funk(int a, int b, int c = 1);

Example 4-1 - The Circle Class with a constructor and destructor

1      // File: ex4-1.cpp - the circle class with ctor and dtor
2     
3      #include <iostream>
4      using namespace std;
5     
6      class circle
7      {
8        private:
9            double radius;
10        public:
11            circle(double);
12            ~circle();
13            double area(void) const;
14            void display(void) const;
15      };
16     
17      circle::circle(double r)                         // constructor
18      {
19        radius = r;
20      }
21     
22      circle::~circle()                              // destructor
23      {
24        cout << "The destructor is called now\n";
25      }
26     
27      double circle::area(void) const
28      {
29        return 3.14 * radius * radius;
30      }
31     
32      void circle::display(void) const
33      {
34        cout << radius << endl;
35        return;
36      }
37     
38      int main(void)
39      {
40        circle c(5.);       // an instance (object) of circle class
41        cout << "The area of circle c is " << c.area() << endl;
42        cout << "Circle c has radius ";
43        c.display();
44        return 0;
45      }


******  Output  ******

The area of circle c is 78.5
Circle c has radius 5
The destructor is called now

Example 4-2 - Constructor/Destructor Execution with respect to Scope

1      // File: ex4-2.cpp
2     
3      #include <iostream>
4      using namespace std;
5     
6     
7      class test
8      {
9          char ch;
10        public:
11          test(char c);                                  // constructor
12          ~test();                                      // destructor
13      };
14     
15      test::test(char c)
16      {
17        ch = c;
18        cout << "*** constructor called for object " << ch <<endl;
19      }
20     
21      test::~test()
22      {
23        cout << "destructor called for object " << ch << endl;
24      }
25     
26      int main(void)
27      {
28        test a(‘a’);
29        {
30            test b(‘b’);
31        }
32        {
33            test c(‘c’);
34            {
35                test d(‘d’);
36            }
37        }
38        return 0;
39      }


******  Output  ******

*** constructor called for object a
*** constructor called for object b
destructor called for object b
*** constructor called for object c
*** constructor called for object d
destructor called for object d
destructor called for object c
destructor called for object a

Example 4-3 - Constructor and Destructor

1      // File: ex4-3.cpp - the person class with ctor & dtor
2     
3      #include <iostream>
4      #include <cstring>
5      #include <cstdlib>
6      using namespace std;
7     
8      class person
9      {
10        private:
11          char* name;
12        public:
13          person(const char *);                     // constructor
14          ~person();                                 // destructor
15          void print(void) const;         // display person's name
16      };
17     
18      person::person(const char* n)
19      {
20        name = new char[strlen(n)+1];
21        strcpy(name,n);
22      }
23     
24      person::~person(void)
25      {
26        delete[] name;
27      }
28     
29      void person::print(void) const
30      {
31        cout << name << endl;
32        return;
33      }
34     
35      int main(void)
36      {
37        person mary("Mary");
38        person joe("Joe");
39        mary.print();
40        joe.print();
41        return 0;
42      }


******  Output  ******
Mary
Joe

Example 4-4 - The card and deck Classes

This example illustrates a containment relationship between classes.

1      // File: ex4-4.cpp
2     
3      #include <iostream>
4      #include <cstdlib>                // needed for rand() function
5      using namespace std;
6     
7      const char* value_name[13] = {"two","three","four","five","six",
8          "seven","eight","nine","ten","jack","queen","king","ace"};
9     
10      const char* suit_name[4] = {"clubs","diamonds","hearts","spades"};
11     
12      class card
13      {
14        private:
15           int value;
16           int suit;
17        public:
18            card() {}
19           card(int);
20           int get_value(void) { return value;}     // accessor function
21           int get_suit(void) { return suit;}     // accessor function
22           void print(void);
23      };
24     
25      card::card(int x)            // constructor
26      {
27        value = x % 13;
28        suit = x / 13;
29      }
30     
31      void card::print(void)
32      {
33        cout << (value_name[value]) << " of "
34           << (suit_name[suit]) << endl;
35        return;
36      }
37     
38     
39      class deck
40      {
41        private:
42           card d[52];
43           int next_card;
44        public:
45           deck(void);
46           void shuffle(void);
47           void deal(int=5);
48           void print(void);
49      };
50     
51      deck::deck(void)
52      {
53        for (int i = 0; i < 52; i++) d[i] = card(i);
54        next_card = 0;
55      }
56     
57     
58      void deck::shuffle(void)
59      {
60        int i, k;
61        card temp;
62        cout << "I am shuffling the deck\n";
63        for (i = 0; i < 52; i++)
64        {
65           k = rand() % 52;
66           temp = d[i];
67           d[i] = d[k];
68           d[k] = temp;
69        }
70        return;
71      }
72     
73      void deck::print(void)
74      {
75        for (int i = 0; i < 52; i++)
76           d[i].print();
77        return;
78      }
79     
80      void deck::deal(int no_of_cards)
81      {
82        cout << "\nOk, I will deal you " << no_of_cards << " cards:\n";
83        for (int i = 0; i < no_of_cards; i++)
84           d[next_card++].print();
85        return;
86      }
87     
88     
89      int main (void)
90      {
91        deck poker;
92        poker.shuffle();
93        poker.print();
94        poker.deal();
95        poker.deal(3);
96        return 0;
97      }


Output similar to Example 3-7

How does line 53 work?  What does d[i] = card(i) mean?
How many constructor calls result from the deck instantiation on line 91?

Example 4-5 – The card and deck Classes Again

This example illustrations a more sophisticated approach to the card and deck classes and more interesting constructors and a destructor.

1      // File: ex4-5.cpp
2     
3      #include <iostream>
4      #include <cstdlib>            // needed for rand() function
5      using namespace std;
6     
7      const char* value_name[13] = {"two","three","four","five","six",
8          "seven","eight","nine","ten","jack","queen","king","ace"};
9     
10      const char* suit_name[4] = {"clubs","diamonds","hearts","spades"};
11     
12      class card
13      {
14        private:
15           int value;
16           int suit;
17        public:
18           card(int=0);
19           int get_value(void) { return value;}     // accessor function
20           int get_suit(void) { return suit;}     // accessor function
21           void print(void);
22      };
23     
24      card::card(int x)
25      {
26        x = abs(x)%52;            // make sure x is between 0 and 51
27        value = x % 13;
28        suit = x / 13;
29      }
30     
31      void card::print(void)
32      {
33        cout << (value_name[value]) << " of "
34           << (suit_name[suit]) << endl;
35        return;
36      }
37     
38     
39      class deck
40      {
41        private:
42           card**  d;
43           int size;
44           int next_card;
45        public:
46           deck(int s = 52);
47           ~deck(void);
48           void shuffle(void);
49           void deal(int=5);
50           void print(void);
51      };
52     
53      deck::deck(int s)
54      {
55        size = s;
56        d = new card*[size];
57        for (int i = 0; i < size; i++) d[i] = new card(i);
58        next_card = 0;
59      }
60     
61      deck::~deck(void)
62      {
63        for (int i = 0; i < size; i++) delete d[i];
64        delete [] d;
65        cout << "The deck is gone" << endl;
66      }
67     
68      void deck::shuffle(void)
69      {
70        int i, k;
71        card* temp;
72        cout << "I am shuffling the deck\n";
73        for (i = 0; i < size; i++)
74        {
75           k = rand() % size;
76           temp = d[i];
77           d[i] = d[k];
78           d[k] = temp;
79        }
80        return;
81      }
82     
83      void deck::print(void)
84      {
85        for (int i = 0; i < size; i++)
86           d[i]->print();        // same as (*d[i]).print()
87        return;
88      }
89     
90      void deck::deal(int no_of_cards)
91      {
92        cout << "\nOk, I will deal you " << no_of_cards << " cards:\n";
93        for (int i = 0; i < no_of_cards; i++)
94           d[next_card++]->print();
95        return;
96      }
97     
98     
99      int main (void)
100      {
101        deck poker;
102        poker.shuffle();
103        poker.print();
104        poker.deal();
105        poker.deal(3);
106        return 0;
107      }


Output similar to Example 3-7

In line 57, how does the expression d[i] = new card(i) work ?
What is better about this approach over the last example?

Example 4-6 - When is a Constructor called?

1      File:  ex4-6.cpp
2     
3      #include <iostream>
4      using namespace std;
5     
6      class Z {
7        public:
8          Z(void) { cout << "Z's constructor is called now\n";}
9      };
10     
11      int main(void) {
12        cout << "\n1. Is the constructor called?\n";
13        Z z;                                       // declare a Z
14        cout << "\n2. Is the constructor called?\n";
15        Z bunch[3];                       // declare a bunch of Zs
16        cout << "\n3. Is the constructor called?\n";
17        Z* ptrZ;                         // declare a pointer to Z
18        cout << "\n4. Is the constructor called?\n";
19        Z* a_new_prtZ = new Z;          // allocate memory for a Z
20        cout << "\n5. Is the constructor called?\n";
21        Z* threeZ = new Z[3];          // allocate memory for 3 Zs
22        cout << "\n6. Is the constructor called?\n";
23        Z** ptr_ptr_Z;              // declare a ptr to ptr to a Z
24        cout << "\n7. Is the constructor called?\n";
25        Z** ptr_ptr_newZ = new Z*;   // alloc mem for a ptr to a Z
26        return 0;
27      }


******  Output  ******

1. Is the constructor called?
Z's constructor is called now

2. Is the constructor called?
Z's constructor is called now
Z's constructor is called now
Z's constructor is called now

3. Is the constructor called?

4. Is the constructor called?
Z's constructor is called now

5. Is the constructor called?
Z's constructor is called now
Z's constructor is called now
Z's constructor is called now

6. Is the constructor called?

7. Is the constructor called?

Example 4-7 - When is a Constructor called?

1      // File:  ex4-7.cpp
2     
3      #include <iostream>
4      using namespace std;
5     
6      class Z
7      {
8        public:
9            Z(void)                                 // constructor
10            {
11             cout << "Z's constructor is called now" << endl;
12            }
13            ~Z()                                    // destructor
14            {
15                cout << "Z's destructor is called now" << endl;
16            }
17      };
18     
19      Z funk1(Z hey)
20      {
21        cout << "This is funk1\n";
22        return hey;
23      }
24     
25      int main(void)
26      {
27        Z temp;
28        funk1(temp);
29        return 0;
30      }


******  Output  ******

Z's constructor is called now
This is funk1
Z's destructor is called now
Z's destructor is called now
Z's destructor is called now

What is going on?

Example 4-8 - When is a Constructor called?

1      // File: ex4-8.cpp
2     
3      #include <iostream>
4      using namespace std;
5     
6      class Z
7      {
8        public:
9            Z(void)
10            {
11             cout << "Z's default constructor is called now\n";
12            }
13            Z(const Z& zed)
14            {
15             cout << "Z's copy constructor is called now" << endl;
16            }
17            ~Z()
18            {
19                cout << "Z's destructor is called now" << endl;
20            }
21      };
22     
23      Z funk1(Z hey)
24      {
25        cout << "This is funk1\n";
26        return hey;
27      }
28     
29      int main(void)
30      {
31        Z temp;
32        funk1(temp);
33        return 0;
34      }


******  Output  ******

Z's default constructor is called now
Z's copy constructor is called now
This is funk1
Z's copy constructor is called now
Z's destructor is called now
Z's destructor is called now
Z's destructor is called now

What happened?
Example 4-9 - The Person and People Classes

1      // File: ex4-9.cpp
2     
3      #include <iostream>
4      #include <cstring>
5      #include <cstdlib>
6      using namespace std;
7     
8      class Person
9      {
10      private:
11           char* name;
12      public:
13           Person(const char *);       // constructor
14           ~Person();
15           void print(void) const;           // display Person's name
16      };
17     
18     
19      Person::Person(const char* n)
20      {
21        name = new char[strlen(n)+1];
22        if (name == 0)
23        {
24           cerr << "Insufficent memory to store " << n << endl;
25           exit(1);
26        }
27        strcpy(name,n);
28      }
29     
30     
31      Person::~Person()
32      {
33        cout << "Person destructor call for " << name << endl;
34        delete [] name;
35      }
36     
37     
38      void Person::print(void) const
39      {
40        cout << name << endl;
41        return;
42      }
43     
44     
45      class People
46      {
47        private:
48           Person** array;
49           int Person_index;    // Person index
50           int Max_People;    // number of People in array
51        public:
52           People(int);
53           ~People();
54           void addPerson(void);
55           void print(void) const;
56      };
57     
58     
59      People::People(int nope)
60      {
61        Max_People = nope;
62        array = new Person*[Max_People];
63        Person_index = 0;
64      }
65     
66     
67      People::~People()
68      {
69        cout << "\nPeople destructor called" << endl;
70        for (int i = 0; i < Max_People; i++)
71        {
72          cout << "deleting pointer to Person[" << i << "]\n";
73          delete array[i];
74        }
75        delete [] array;
76      }
77     
78     
79      void People::addPerson(void)
80      {
81        char temp[20];
82        cout<<"Enter the Persons name => ";
83        cin >> temp;
84        array[Person_index++] = new Person(temp);
85        return;
86      }
87     
88     
89      void People::print(void) const
90      {
91        cout << "\nHere's the People:\n";
92        for (int i = 0; i < Person_index; i++) array[i]->print();
93        return;
94      }
95     
96     
97      int main (void)
98      {
99        cout << "How many friends do you have? ";
100        int no_friends;
101        cin >> no_friends;
102        People friends(no_friends);
103        for (int i = 0; i < no_friends; i++) friends.addPerson();
104        friends.print();
105        return 0;
106      }


*****  Sample Run  ******

How many friends do you have? 5
Enter the persons name => Henry
Enter the persons name => Hubert
Enter the persons name => Hank
Enter the persons name => Hilbert
Enter the persons name => Hellbert

Here's the people:
Henry
Hubert
Hank
Hilbert
Hellbert

People destructor called
deleting pointer to person[0]
Person destructor call for Henry
deleting pointer to person[1]
Person destructor call for Hubert
deleting pointer to person[2]
Person destructor call for Hank
deleting pointer to person[3]
Person destructor call for Hilbert
deleting pointer to person[4]
Person destructor call for Hellbert

What does a People object look like?
What caused each destructor call to Person?
No copy constructors were provided for either the Person class or the People class.  Is that a good idea?  How would you write them?

  1. Constructors 為特殊的 class member functions 來建立 class objects. 它們在 instance 建立時自動執行. 它的名稱與 class 名稱相同.
  2. Destructors 為 objects 離開時自動執行的 function. 它的名稱為 class 名稱前加 ~. Destructors 主要用途為 release dynamic allocated memory.
  3. Overload functions 的 function 名稱相同, 但不同的 arguments.

沒有留言:

張貼留言