2012年1月19日 星期四
Default Constructor
The Default Constructor
A default constructor is the constructor that is executed when no arguments are provided in the declaration. There are three possible situations for
this:
1. If you do not provide any constructor for a class, the compiler-provided one is considered the default constructor. It, of course, does not do anything other than allocating memory for the class object.
This looks like:
class x
{
… // no constructors defined for the class
};
2. If you provide a constructor without any arguments (void), then that is the class default constructor.
This looks like:
class x
{
…
x(); // or x(void);
…
};
3. If you provide a constructor with all default arguments, then, that, too, may be considered the default constructor. Warning: you may not have a class with both a void-argument constructor and one with all default arguments.
This looks like:
class x
{
…
x(int x=5); // Note: the only argument is a default argument
…
};
or maybe like this:
class x
{
…
x(double d = 0.0, unsigned short s=0); // Two default arguments
…
};
Instantiation of an Object Using the Default Constructor
Objects are declared using the default constructor without parentheses, not even empty parentheses.
For example, to declare (instantiate an object) using any one of the x classes from the previous page, you would write it as:
x object;
or
… new x;
or
… new x();
not
x object();
Why can't you declare a class object with parentheses using the default constructor?
Answer:
Suppose you write a function like this:
void funk()
{
…
x object();
…
}
The problem is that the statement, x object();, can take on two meanings. It looks just like a function prototype (a function called object with a
void argument and an x return) and now you want to use it to instantiate an x object? I don't think so. You compiler refuses to be confused.
Instantiation of an Object Using the Default Constructor
Objects are declared using the default constructor without parentheses, not even empty parentheses.
For example, to declare (instantiate an object) using any one of the x classes from the previous page, you would write it as:
x object;
or
… new x;
or
… new x();
not
x object();
Why can't you declare a class object with parentheses using the default constructor?
Answer:
Suppose you write a function like this:
void funk()
{
…
x object();
…
}
The problem is that the statement, x object();, can take on two meanings. It looks just like a function prototype (a function called object with a void argument and an x return) and now you want to use it to instantiate an x object? I don't think so. You compiler refuses to be confused.
A default constructor 被執行是當在 declaration 中沒有 arguments 提供.
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 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.
Command-line Compilation
Command-line Compilation
Microsoft Visual C++ 2008 compiler
Before you can perform a command-line compile, you must run vcvars32.bat. This program and the cl.exe for the command-line compile are found in the directory: \Program Files\Microsoft Visual Studio 9.0\VC\bin
C:\deanza\cis27\examples>vcvars32
C:\deanza\cis27\examples>"c:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
C:\deanza\cis27\examples>cl ex3-11.cpp ex3-11c.cpp ex3-11d.cpp /EHsc
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
ex3-11.cpp
ex3-11c.cpp
ex3-11d.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 9.00.21022.08
Copyright (C) Microsoft Corporation. All rights reserved.
/out:ex3-11.exe
ex3-11.obj
ex3-11c.obj
ex3-11d.obj
GNU compiler
g++ ex3-11.cpp ex3-11c.cpp ex3-11d.cpp -Wall
Microsoft Visual C++ 2008 與 GNU compiler, Command line compilation
Multi-File C++ Programs
Multi-File C++ Programs
It is common practice in larger C++ programs to separate the application into multiple files. The files typically consist of one or more header files, function definition files, and a file to hold main(). The header files generally contain class definitions, constants, enumerated types, structures, typedefs, and inline function definitions. Header files have the same name as the class or a name related to the application and have the extension .h (.hpp on some compilers). Class member function definitions are contained in another file(s). The filename is often the same name as the class name and extension .cpp (or whatever the requirement for your compiler). This file(s) should "include" the header file(s) and may be compiled separately. The file containing main() will usually have the name of the application and the usual C++ extension. main() will need to include the header file(s) and after compilation will link to the compiled class member definition file(s). This process is managed for you in many of the PC and Mac compilers with projects.
This example is logically the same as Example 3-7.
Example 3-11 - A Multi-file program
1 // File: ex3_11c.h - card class definition
2
3 #ifndef EX3_11C_H
4 #define EX3_11C_H
5
6 class card
7 {
8 private:
9 int value;
10 int suit;
11 public:
12 void assign(int);
13 int get_value(void) const;
14 int get_suit(void) const;
15 void print(void) const;
16 };
17
18 #endifNote: some compilers do not support header files with a hyphen in the file name.
1 // File: ex3_11d.h - deck class definition
2 #ifndef EX3_11D_H
3 #define EX3_11D_H
4 #include "ex3_11c.h"
5
6 class deck
7 {
8 private:
9 card d[52];
10 int next_card;
11 public:
12 void create_deck(void);
13 void shuffle(void);
14 void deal(int=5);
15 void print(void) const;
16 };
17 #endif
1 // File: ex3-11c.cpp card class member function definitions
2
3 #include <iostream>
4 using namespace std;
5
6 #include "ex3_11c.h"
7
8 const char* value_name[13] =
9 {"two","three","four","five","six",
10 "seven","eight","nine","ten","jack","queen","king","ace"};
11 const char* suit_name[4] =
12 {"clubs","diamonds","hearts","spades"};
13
14 card::get_value(void) const {
15 return value;
16 }
17
18 int card::get_suit(void) const {
19 return suit;
20 }
21
22 void card::assign(int x) {
23 value = x % 13;
24 suit = x / 13;
25 return;
26 }
27
28 void card::print(void) const {
29 cout << (value_name[value]) << " of "
30 << (suit_name[suit]) << endl;
31 return;
32 }
1 // File: ex3-11d.cpp - deck class member function definitions
2
3 #include <iostream>
4 #include <cstdlib> // needed for rand() function
5 using namespace std;
6
7 #include "ex3_11d.h"
8
9 void deck::create_deck(void) {
10 for (int i = 0; i < 52; i++) d[i].assign(i);
11 next_card = 0;
12 }
13
14 void deck::shuffle(void) {
15 int i, k;
16 card temp;
17 cout << "I am shuffling the deck\n";
18 for (i = 0; i < 52; i++) {
19 k = rand() % 52;
20 temp = d[i];
21 d[i] = d[k];
22 d[k] = temp;
23 }
24 }
25
26 void deck::print(void) const {
27 cout << "\nHere's the deck:\n";
28 for (int i = 0; i < 52; i++) d[i].print();
29 }
30 void deck::deal(int no_of_cards) {
31 cout <<"\nOk, I will deal you "<<no_of_cards<<" cards:\n";
32 for (int i = 0;i<no_of_cards; i++) d[next_card++].print();
33 }
1 // File: ex3-11.cpp - main()
2
3 #include "ex3_11d.h"
4
5 int main (void) {
6 deck poker;
7 poker.create_deck();
8 poker.print();
9 poker.shuffle();
10 poker.print();
11 poker.deal();
12 poker.deal(3);
13 return 0;
14 }The output is the same as examples 3-7.
比較大的 C++ 程式分為幾個檔案: 一或多個 header files, function definition files, 和 main file.
Nested Classes
Nested Classes
This example illustrates nested classes. Note the use of the scope resolution operator in the member function definitions. This example is logically the same as example 3-7.
Example 3-10 - Nested Classes
1 // File: ex3-10.cpp - the card and deck example with nested classes
2
3 #include <iostream>
4 #include <stdlib>
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 const char* suit_name[4] =
10 {"clubs","diamonds","hearts","spades"};
11
12
13 class deck
14 {
15 public: // Why is this public?
16 class card
17 {
18 private:
19 int value;
20 int suit;
21 public:
22 void assign(int);
23 int get_value(void) const;
24 int get_suit(void) const;
25 void print(void) const;
26 };
27
28 private:
29 card d[52];
30 int next_card;
31 public:
32 void create_deck(void);
33 void shuffle(void);
34 void deal(int=5);
35 void print(void) const;
36 };
37
38
39 int deck::card::get_value(void) const
40 {
41 return value;
42 }
43
44 int deck::card::get_suit(void) const
45 {
46 return suit;
47 }
48
49 void deck::card::assign(int x)
50 {
51 value = x % 13;
52 suit = x / 13;
53 }
54
55 void deck::card::print(void) const
56 {
57 cout << (value_name[value]) << " of "
58 << (suit_name[suit]) << endl;
59 return;
60 }
61
62 void deck::create_deck(void)
63 {
64 for (int i = 0; i < 52; i++) d[i].assign(i);
65 next_card = 0;
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 < 52; i++)
74 {
75 k = rand() % 52;
76 temp = d[i];
77 d[i] = d[k];
78 d[k] = temp;
79 }
80 }
81
82 void deck::print(void) const
83 {
84 cout << "\nHere's the deck:\n";
85 for (int i = 0; i < 52; i++) d[i].print();
86 }
87
88 void deck::deal(int no_of_cards)
89 {
90 cout <<"\nOk, I will deal you "<<no_of_cards<<" cards:\n";
91 for (int i=0;i<no_of_cards; i++) d[next_card++].print();
92 return;
93 }
94 int main (void)
95 {
96 // card C; // Why is this commented out?
97 deck::card C; // Instatiate a card object
98 C.assign(17);
99 C.print(); // prints six of diamonds
100
101 deck poker;
102 poker.create_deck();
103 poker.print();
104 poker.shuffle();
105 poker.print();
106 poker.deal();
107 poker.deal(3);
108 return 0;
109 }****** Output same as Example 3-7 ******
Note: A nested class, like the card class of this example, is subject to access specifiers, just like data members or member functions. In other words, if the card class within the deck class of this example is specified as private, then the card type is not visible except to deck class member functions.
Nested class 的從屬關係就如同它 access specifiers 的定義.
2012年1月17日 星期二
Mutable and Enumerated Type
mutable
You haven't heard the entire truth about const member functions. The definition stated earlier was, "A const member function is a class member function that may not make any changes to any of the data members of the class". Actually, there is an exception to this. The keyword, mutable, allows the user to supersede the const intension. A class member that is defined using the storage specifier, mutable, may be changed in a const member function. Here is example 3-8 again with a mutable class member:
1 // File: ex3-8m.cpp - const member function with a mutable member
2
3 void makeit6(int& I)
4 {
5 I = 6;
6 }
7
8
9 class ABC
10 {
11 mutable int x;
12 public:
13 void funk();
14 void gunk() const; // const member function
15 void hunk(int&);
16 void junk(int&) const; // const member function
17 void lunk(const int&);
18 void munk(const int&) const; // const member function
19 };
20
21 void ABC::funk()
22 {
23 x = 6; // ok
24 makeit6(x); // ok
25 makeit6(6); // error: cannot convert const int to int&
26 }
27
28 void ABC::gunk() const
29 {
30 x = 6; // ok
31 makeit6(x); // ok
32 }
33
34 void ABC::hunk(int &I)
35 {
36 x = 6; // ok
37 makeit6(I); // ok
38 makeit6(x); // ok
39 }
40
41 void ABC::junk(int &I) const
42 {
43 x = I; // ok
44 makeit6(I); // ok
45 makeit6(x); // ok
46 }
47
48
49 void ABC::lunk(const int &I)
50 {
51 x = I; // ok
52 makeit6(I); // error: cannot pass const int& as int&
53 makeit6(x); // ok
54 }
55
56 void ABC::munk(const int &I) const
57 {
58 x = I; // ok
59 makeit6(I); // error: cannot pass const int& as int&
60 makeit6(x); // ok
61 }
62
63
64 int main()
65 {
66 ABC object;
67 int i = 3;
68 object.funk();
69 object.gunk();
70 object.hunk(i);
71 object.junk(i);
72 object.lunk(i);
73 object.munk(i);
74
75 return 0;
76 }No output – compile errors
mutable should be used in a situation where you want a member function to only be able to change a few of the class members, not all of them.
Classes Containing Enumerated Types
Example 3-9 - Enums and classes
1 // File: ex3-9.cpp - enums and classes
2
3 #include <iostream>
4 using namespace std;
5
6 enum size {small, medium, large};
7
8 class thing
9 {
10 public:
11 enum color {red, white, blue};
12 enum {FALSE, TRUE }; // anonymous enum
13 void setBigness(size=small);
14 void setHue(color=red);
15 size getBigness() const;
16 color getHue() const;
17 int amIBlue() const
18 { if (hue == blue) return TRUE; else return FALSE; }
19 private:
20 size bigness;
21 color hue;
22 };
23
24 void thing::setBigness(size s)
25 {
26 bigness = s;
27 }
28
29 void thing::setHue(color c)
30 {
31 hue = c;
32 }
33
34 size thing::getBigness() const
35 {
36 return bigness;
37 }
38
39 thing::color thing::getHue() const // note difference to prototype
40 { // this is required
41 return hue;
42 }
43
44
45 thing::color nonMember(const thing&); // function prototype
46 int main() {
47 size S = large;
48 thing::color C = thing::white;
49
50 thing Big_red_thing;
51 Big_red_thing.setBigness(S);
52 Big_red_thing.setBigness(medium);
53 Big_red_thing.setHue();
54 cout << "I am"
55 << (Big_red_thing.amIBblue() ? " " : " not ")
56 << "blue\n";
57
58 thing Little_blue_thing;
59 Little_blue_thing.setBigness();
60 // Little_blue_thing.setHue(blue);
61 Little_blue_thing.setHue(thing::blue);
62 cout << "I am"
63 << (Little_blue_thing.amIBlue() ? " " : " not ")
64 << "blue\n";
65 Little_blue_thing.setHue(C);
66 cout << "I am"
67 << (Little_blue_thing.amIBlue() ? " " : " not ")
68 << "blue\n";
69
70 nonMember(Big_red_thing);
71
72 return 0;
73 }
74
75 thing::color nonMember(const thing& T) {
76 return T.getHue();
77 }****** Output ******
I am not blue
I am blue
I am not blue
Note: An enumerated type defined within a class is subject to access specifiers, just like data members or member functions. In other words, if the color type in the thing class of this example is specified as private, then that type is not visible except to class member functions.
當你想要 member function 可以改變部分的 class members, 可以使用 mutable.
enumerated type 的 access specifiers 與 data members 與 member functions 相同.
Const Member Functions
const member functions
A const member function is a class member function that may not make any changes to any of the data members of the class. A const member function is identified by appending the keyword, const, to both the prototype and the heading of the function definition.
The following example demonstrates const member functions. It constains several compilation errors.
1 // File: ex3-8.cpp – const member functions
2
3 void makeit6(int& I)
4 {
5 I = 6;
6 }
7
8
9 class ABC
10 {
11 int x;
12 public:
13 void funk();
14 void gunk() const; // const member function
15 void hunk(int&);
16 void junk(int&) const; // const member function
17 void lunk(const int&);
18 void munk(const int&) const; // const member function
19 };
20
21 void ABC::funk()
22 {
23 x = 6; // ok
24 makeit6(x); // ok
25 makeit6(6); // error: cannot convert const int to int&
26 }
27
28 void ABC::gunk() const
29 {
30 x = 6; // error: cannot change data member in CMF
31 makeit6(x); // error: cannot pass const int as int&
32 }
33
34 void ABC::hunk(int &I)
35 {
36 x = 6; // ok
37 makeit6(I); // ok
38 makeit6(x); // ok
39 }
40
41 void ABC::junk(int &I) const
42 {
43 x = I; // error: cannot change data member in CMF
44 makeit6(I); // ok
45 makeit6(x); // error: cannot pass const int as int&
46 }
47
48
49 void ABC::lunk(const int &I)
50 {
51 x = I; // ok
52 makeit6(I); // error: cannot pass const int& as int&
53 makeit6(x); // ok
54 }
55
56 void ABC::munk(const int &I) const
57 {
58 x = I; // error: cannot change data member in CMF
59 makeit6(I); // error: cannot pass const int& as int&
60 makeit6(x); // error: cannot pass const int as int&
61 }
62
63
64 int main()
65 {
66 ABC object;
67 int i = 3;
68 object.funk();
69 object.gunk();
70 object.hunk(i);
71 object.junk(i);
72 object.lunk(i);
73 object.munk(i);
74
75 return 0;
76 }No output – compile errors
Make sure that you are clear on the difference between a const member function and one with a reference to const argument.
Note: in example 3-8 above, lunk() is not a const member function. It is a member function with a reference to const argument.
const member function 是 class member function, 它無法變更 class 的 data members.
2012年1月13日 星期五
Inline Functions
Inline Functions
Functions, either class members or non-class member functions, may be defined as inline. An inline function is one in which the function code replaces the function call directly. Specifying that a function be inline is a request to the compiler that it be inline, but the
compiler may choose not to make it an inline function. This is transparent to the user. Inline functions should be short (preferable one-liners).
Inline class member functions may be implicit, if they are defined as part of the class definition, or explicit if they are defined outside of the class definition using the keyword, inline.
Inline functions have only internal linkage, that is, they are local to the file in which they are defined.
Example
class xyz
{
private:
.
.
.
public:
void funk1(void) { cout << "Have a nice day\n"; return; }
void funk2(void);
.
.
};
inline void xyz::funk2(void)
{
cout << "Ok, don't have a nice day\n";
return;
}
.
.
int main(void)
{
xyz a,b;
a.funk1();
b.funk2();
.
.
funk1 is an implicit inline function. funk2 is an explicit inline function.
Example 3-4 - The Clock class
1 // File: ex3-4.cpp - the Clock class
2
3 #include <iostream>
4 using namespace std;
5
6 class Clock
7 {
8 private:
9 int hours;
10 int minutes;
11 int seconds;
12 public:
13 void set(int h, int m, int s)
14 {hours = h; minutes = m; seconds = s; return;} // inline
15 void increment(void);
16 void display(int=0) const;
17 };
18
19
20 void Clock::increment (void)
21 {
22 seconds++;
23 minutes += seconds/60;
24 hours += minutes/60;
25 seconds %= 60;
26 minutes %= 60;
27 hours %= 24;
28 return;
29 }
30
31
32 void Clock::display(int format) const
33 {
34 if (format) { // use format hh:mm:ss AM/PM
35 cout << (hours % 12 ? hours % 12:12) << ':'
36 << (minutes < 10 ? "0" :"") << minutes << ':'
37 << (seconds < 10 ? "0" :"") << seconds
38 << (hours < 12 ? " AM" : " PM") << endl;
39 }
40 else { // use format hh:mm:ss (24 hour time)
41 cout << (hours < 10 ? "0" :"") << hours << ':'
42 << (minutes < 10 ? "0" :"") << minutes << ':'
43 << (seconds < 10 ? "0" :"") << seconds << endl;
44 }
45 }
46
47
48 int main(void)
49 {
50 Clock c;
51 c.set(23,59,55);
52 for (int i = 0; i < 10; i++) {
53 c.increment();
54 c.display();
55 c.display(1);
56 cout << endl;
57 }
58 return 0;
}****** Output ******
23:59:56
11:59:56 PM
23:59:57
11:59:57 PM
23:59:58
11:59:58 PM
23:59:59
11:59:59 PM
00:00:00
12:00:00 AM
00:00:01
12:00:01 AM
00:00:02
12:00:02 AM
00:00:03
12:00:03 AM
00:00:04
12:00:04 AM
00:00:05
12:00:05 AM
Example 3-5 - The Date class
1 // File: ex3-5.cpp - The Date class
2
3 #include <iostream>
4 #include <cstring>
5 #include <cstdlib>
6 using namespace std;
7
8 const unsigned DaysPerMonth[] =
9 {31,28,31,30,31,30,31,31,30,31,30,31};
10
11 class Date
12 {
13 unsigned day;
14 unsigned month;
15 unsigned year;
16 void errmsg(const char* msg);
17 public:
18 void set(const char* mmddyy);
19 void increment(void);
20 void display(void) const;
21 };
22
23 void Date::set(const char* mm_dd_yy)
24 {
25 char* temp;
26 char copy[9];
27
28 // assume user enters date as mm/dd/yy
29 if (strlen(mm_dd_yy) != 8) errmsg(mm_dd_yy);
30
31 // use a copy of mm_dd_yy What is the impact to the function?
32 strcpy(copy,mm_dd_yy);
33
34 // parse the date and get the month
35 temp = strtok(copy,"/"); // strtok() replaces "/" with a NULL
36 if (temp != NULL) month = atoi(temp);
37 else errmsg(copy);
38
39 // parse the date and get the day
40 temp = strtok(NULL,"/"); // strtok() finds the next "/"
41 if (temp != NULL) day = atoi(temp);
42 else errmsg(copy);
43
44 // parse the date and get the year
45 temp = strtok(NULL,"/");
46 if (temp != NULL) year = atoi(temp);
47 else errmsg(copy);
48
49 // Make a Y2K correction for a 2-digit year
50 if (year < 50) year += 2000;
51 else if (year < 100) year += 1900;
52 else ; // assume the year is right
53 }
54
55 void Date::increment (void)
56 {
57 // increment the day
58 day++;
59
60 // check for the end of the month
61 if (day > DaysPerMonth[month - 1]) // past end of current month?
62 {
63 month ++;
64 day = 1;
65 }
66
67 // check for the end of the year
68 if (month > 12)
69 {
70 year ++;
71 month = 1;
72 }
73
74 return;
75 }
76
77 void Date::display(void) const
78 {
79 cout << "The date is " << month << '/' << day << '/'
80 << (year%100< 10?"0":"") << year%100 << endl;
81 if (day % DaysPerMonth[month-1] == 0) cout << endl;
82 return;
83 }
84
85 void Date::errmsg(const char* msg)
86 {
87 cerr << "Invalid date format: " << msg << endl;
88 exit(EXIT_FAILURE);
89 }
90
91 int main(void)
92 {
93 Date d;
94 char mmddyy[9];
95 cout << "Enter the starting date <mm/dd/yy> => ";
96 cin >> mmddyy;
97 d.set(mmddyy);
98 for (int i = 0; i < 375; i++)
99 {
100 d.display();
101 d.increment();
102 }
103 return 0;
104 }****** Sample Output #1 ******
Enter the starting date <mm/dd/yy> => 4/20/09
Invalid date format: 1/20/09
****** Sample Output #2 ******
Enter the starting date <mm/dd/yy> => 04/20/09
The date is 4/20/09
The date is 4/21/09
The date is 4/22/09
The date is 4/23/09
The date is 4/24/09
The date is 4/25/09
The date is 4/26/09
The date is 4/27/09
The date is 4/28/09
The date is 4/29/09
The date is 4/30/09
The date is 5/1/09
The date is 5/2/09
The date is 5/3/09
The date is 5/4/09
The date is 5/5/09
The date is 5/6/09
The date is 5/7/09
The date is 5/8/09
The date is 5/9/09
The date is 5/10/09
…
The date is 12/29/09
The date is 12/30/09
The date is 12/31/09
The date is 1/1/10
The date is 1/2/10
The date is 1/3/10
The date is 1/4/10
The date is 1/5/10
The date is 1/6/10
…
The date is 4/24/10
The date is 4/25/10
The date is 4/26/10
The date is 4/27/10
The date is 4/28/10
The date is 4/29/10
What is the effect of making errmsg() private in the class?
How does strtok() work?
Is there a difference if line 40 is coded like this? temp = strtok(NULL,"/");
No, not really, in C++ the macro NULL is defined as (integer) 0.
How would you make this program work for leap years?
How would you change display() to print the date with a two-digit month and day?
What is atoi() and how does it work? Why is it not considered "safe"?
Practice problem: Modify this program to print the date as "m/dd/yy" and to handle leap years?
Example 3-6 - The quadratic (Equation) class
1 // File: ex3-6.cpp - the quadratic class
2
3 #include <iostream>
4 #include <cmath>
5 using namespace std;
6
7 class quadratic
8 {
9 private:
10 float a, b, c;
11 public:
12 void set(float f1, float f2, float f3)
13 {a = f1; b = f2; c = f3; return;}
14 void solve(void) const;
15 void display(void) const;
16 };
17
18 void quadratic::solve (void) const
19 {
20 bool complex_roots;
21 float radical_stuff;
22 if (a == 0)
23 {
24 cout <<
25 "This is not a quadratic equation. It has only one root "
26 << -c/b << endl;
27 return;
28 }
29 complex_roots = (radical_stuff = b * b - 4 * a * c) < 0;
30 cout << "The roots of the equation are ";
31 if (!complex_roots)
32 cout << ((-b+sqrt(radical_stuff))/(2.*a))
33 <<" and " << ((-b-sqrt(radical_stuff))/(2.*a)) << endl;
34 else
35 cout << (-b/(2.*a)) <<'+'<< sqrt(-radical_stuff)/(2.*a)<<'i'
36 <<
37 " and "
38 << (-b/(2.*a)) << '-' << sqrt(-radical_stuff)/(2.*a) << 'i'
39 <<endl;
40 return;
41 }
42
43 void quadratic::display(void) const
44 {
45 cout << "The coefficients of the quadratic equations are: "
46 << a << ", " << b << ", and " << c <<endl;
47 return;
48 }
49
50 int main(void)
51 {
52 quadratic equation;
53 float a,b,c;
54 while (1)
55 {
56 cout <<
57 “Enter 3 coeffients for a quadratic equation (or quit) => ";
58 if (!(cin >> a >> b >> c)) break;
59 equation.set(a,b,c);
60 equation.display();
61 equation.solve();
62 cout << endl;
63 }
64 return 0;
65 }****** Sample Run ******
Enter 3 coefficients for an equation (or quit) => 1 2 1
The coefficients of the quadratic equations are: 1, 2, and 1
The roots of the equation are -1 and -1
Enter 3 coefficients for an equation (or quit) => 1 0 -1
The coefficients of the quadratic equations are: 1, 0, and -1
The roots of the equation are 1 and -1
Enter 3 coefficients for an equation (or quit) => 1 2 3
The coefficients of the quadratic equations are: 1, 2, and 3
The roots of the equation are -1+1.414214i and -1-1.414214i
Enter 3 coefficients for an equation (or quit) => 1 1 1
The coefficients of the quadratic equations are: 1, 1, and 1
The roots of the equation are -0.5+0.866025i and -0.5-0.866025i
Enter 3 coefficients for an equation (or quit) => 0 3 6
The coefficients of the quadratic equations are: 0, 3, and 6
This is not a quadratic equation. It has only one root -2
Enter 3 coefficients for an equation (or quit) => quit
How does the line: if (!(cin >> a >> b >> c)) break; work?
Example 3-7 - The card and deck classes
This example demonstrates a container relationship between classes. This is also called containment.
1 // File: ex3-7.cpp - card and deck classes
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 void assign(int);
19 int get_value(void) const; // accessor function
20 int get_suit(void) const; // accessor function
21 void print(void) const;
22 };
23
24 void card::assign(int x)
25 {
26 value = x % 13;
27 suit = x / 13;
28 return;
29 }
30
31 int card::get_value(void) const
32 {
33 return value;
34 }
35
36 int card::get_suit(void) const
37 {
38 return suit;
39 }
40
41 void card::print(void) const
42 {
43 cout << (value_name[value]) << " of "
44 << (suit_name[suit]) << endl;
45 return;
46 }
47 class deck
48 {
49 private:
50 card d[52];
51 int next_card;
52 public:
53 void create_deck(void);
54 void shuffle(void);
55 void deal(int=5);
56 void print(void) const;
57 };
58
59
60 void deck::create_deck(void)
61 {
62 for (int i = 0; i < 52; i++) d[i].assign(i);
63 next_card = 0;
64 return;
65 }
66
67
68 void deck::shuffle(void)
69 {
70 int i, k;
71 cout << "I am shuffling the deck\n";
72 for (i = 0; i < 52; i++)
73 {
74 k = rand() % 52;
75 card temp = d[i];
76 d[i] = d[k];
77 d[k] = temp;
78 }
79 return;
80 }
81
82
83 void deck::print(void) const
84 {
85 cout << "\nHere's the deck:\n";
86 for (int i = 0; i < 52; i++) 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++) d[next_card++].print();
94 return;
95 }
96 int main(void) {
97 deck poker;
98 poker.create_deck();
99 poker.print();
100 poker.shuffle();
101 poker.print();
102 poker.deal();
103 poker.deal(3);
104 return 0;
105 }****** Output ******
Here's the deck:
two of clubs
three of clubs
four of clubs
five of clubs
six of clubs
seven of clubs
eight of clubs
nine of clubs
. .
. .
ace of spades
I am shuffling the deck
Here's the deck:
ten of hearts
ace of diamonds
queen of clubs
three of diamonds
four of spades
eight of spades
eight of diamonds
. .
. .
Ok, I will deal you 5 cards:
ten of hearts
ace of diamonds
queen of clubs
three of diamonds
four of spades
Ok, I will deal you 3 cards:
eight of spades
eight of diamonds
eight of clubs
Inline function 為 function code 取代 function call.
訂閱:
意見 (Atom)