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 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?
- Constructors 為特殊的 class member functions 來建立 class objects. 它們在 instance 建立時自動執行. 它的名稱與 class 名稱相同.
- Destructors 為 objects 離開時自動執行的 function. 它的名稱為 class 名稱前加 ~. Destructors 主要用途為 release dynamic allocated memory.
- Overload functions 的 function 名稱相同, 但不同的 arguments.
沒有留言:
張貼留言