21天學通C++(第四版)筆記

sgy618發表於2011-03-11

21天學通C++(第四版)筆記

[@more@]

1 #include
2
3 int main()
4 {
5 std::cout << "Hello World!";
7 return 0;
8 }

會注意到,在cout和endl前面使用std::是煩人事情,可透過兩種方法來搞定
第一種,在程式碼清單開始位置告訴編譯器使用標準庫函式cout和endl。
int main()
{
using std::cout;
using std::endl;
......
}
第二種,告訴編譯器,使用全部的namespace標準,意為沒有特殊指定的任何物件可以假定都來自標準namespace。
int main()
{
using namespace std;
......
}
可以看出,使用using namespace std;的好處是不再需要特殊指定實際使用的物件(cout和endl)

以下開始物件導向
宣告一個類:
class Cat
{
unsigned int itsAge;
unsigned int itWeight;
void Meow();
};
宣告這個類並沒有為Cat分配記憶體。它只告訴編譯器Cat是什麼,它包含什麼資料以及功能是什麼。同事它該告訴編譯器Cat有多大,一個整型佔4個位元組,那麼Cat的大小為8個位元組,Meow不佔空間,因為系統沒有為成員函式(方法)分配儲存空間。

一個類的所有成員(資料和方法)預設時均為私有。私有成員只能在類本身的方法內訪問。共有成員則可以被該類的所有物件訪問。
作為設計的一般規則,應該保持類的成員資料為私有,所以需要建立成為訪問方法的公有函式來設定和獲取私有成員變數。

例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 int getage();
9 void setage(int age);
10 void meow();
11 private:
12 int itsage;
13 };
14
15 int cat::getage()
16 {
17 return itsage;
18 }
19
20 void cat::setage(int age)
21 {
22 itsage = age;
23 }
24
25 void cat::meow()
26 {
27 cout << "meow.-------------- n";
28 }
29
30 int main()
31 {
32 cat frisky;
33 frisky.setage(5);
34 frisky.meow();
35
36 cout << frisky.getage() << " years old.n";
37
38 frisky.meow();
39 return 0;
40
41 }
結果:
meow.--------------
5 years old.
meow.--------------

如果沒有宣告建構函式或解構函式,編譯器會自動建立一個。有許多型別的建構函式,有些需要引數,有些不需要,沒有引數的被稱為預設建構函式。

使用建構函式和解構函式的例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat(int initialage);
9 ~cat();
10 int getage();
11 void setage(int age);
12 void meow();
13 private:
14 int itsage;
15 };
16
17 cat::cat(int initialage)
18 {
19 itsage = initialage;
20 }
21
22 cat::~cat()
23 {
24 }
25
26 int cat::getage()
27 {
28 return itsage;
29 }
30
31 void cat::setage(int age)
32 {
33 itsage = age;
34 }
35
36 void cat::meow()
37 {
38 cout << "----------------------n";
39 }
40
41 int main()
42 {
43 cat frisky(5);
44 frisky.meow();
45
46 cout << frisky.getage() << " years old.n";
47
48 frisky.meow();
49 frisky.setage(7);
50
51 cout << frisky.getage() << " years old.n";
52 return 0;
53 }
結果:
----------------------
5 years old.
----------------------
7 years old.

良好的程式設計習慣儘可能多的方法宣告為const,例如:int GetAge() const;

如果將某個函式的定義放在該類的宣告中,浙江使該函式自動成為內嵌函式。
class Cat
{
public:
int GetWeight(){return itsWeight;} //inline
void SetWeight(int aWeight);
};

C++使用關鍵字new分配自由儲存區中的記憶體。
例如:
unsigned short int *pPointer;
pPointer = new unsigned short int;

unsigned short int *pPointer = new unsigned short int;
相對應用delete來釋放記憶體,例如:delete pPointer;
當使用delete刪除一個指標時,把它賦為0(空指標)。刪除一個空指標是安全的。
在自由儲存區內建立物件,例如:Cat *pCat = new Cat;

自由儲存區的成員資料:例子:
1 #include
2
3 using namespace std;
4
5 class simplecat
6 {
7 public:
8 simplecat();
9 ~simplecat();
10 int getage() const {return *itsage;}
11 void setage(int age) {*itsage = age;}
12
13 int getweight() const {return *itsweight;}
14 void setweight(int weight) {*itsweight = weight;}
15 private:
16 int *itsage;
17 int *itsweight;
18 };
19
20 simplecat::simplecat()
21 {
22 itsage = new int(2);
23 itsweight = new int(5);
24 }
25
26 simplecat::~simplecat()
27 {
28 delete itsage;
29 delete itsweight;
30 }
31
32 int main()
33 {
34 simplecat *frisky = new simplecat;
35 cout << frisky->getage() << " years oldn";
36 frisky->setage(5);
37 cout << frisky->getage() << " years oldn";
38 delete frisky;
39 return 0;
40 }
結果:
2 years old
5 years old

每一個類的成員函式都有一個隱藏的引數 —— this指標,this指標職場每一個單獨的物件
例子:
1 #include
2
3 using namespace std;
4
5 class rectangle
6 {
7 public:
8 rectangle();
9 ~rectangle();
10 void setlength(int length)
11 {
12 this->itslength = length;
13 }
14 int getlength() const
15 {
16 return this->itslength;
17 }
18
19 void setwidth(int width)
20 {
21 itswidth = width;
22 }
23 int getwidth() const
24 {
25 return itswidth;
26 }
27 private:
28 int itslength;
29 int itswidth;
30 };
31
32 rectangle::rectangle()
33 {
34 itswidth = 1;
35 itslength = 2;
36 }
37
38 rectangle::~rectangle()
39 {}
40
41 int main()
42 {
43 rectangle therect;
44 cout << therect.getlength() << "feet long.n";
45 cout << therect.getwidth() << "feet wide.n";
46 therect.setlength(20);
47 therect.setlength(10);
48 cout << therect.getlength() << "feet long.n";
49 cout << therect.getwidth() << "feet wide.n";
50 return 0;
51 }
結果:
2feet long.
1feet wide.
10feet long.
1feet wide.
this是一個指標,儲存了一個物件的地址,即它是一個指向物件自身的指標。

一個對迷途指標的很好的比喻:如同甲公司搬家了,但是你仍然使用原來的號碼,這可能不會導致什麼嚴重後果,也許這個電話放在一個無人居住的房子裡面,但如果這個號碼重新分配給一個軍工廠,你的電話就可能引發爆炸,摧毀整個城市。

預設複製建構函式,它在每次複製一個物件的時候呼叫,當按值傳遞物件時,無論是傳遞到函式內還是作為函式的返回值,均會生產該物件的一個臨時複製。如果這個物件是一個使用者定義的物件,則呼叫這個類的複製建構函式。所有複製建構函式均有一個引數,即對同一類的物件的引用
例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat();
9 cat(const cat &);
10 ~cat();
11 int getage() const {return *itsage;}
12 int getweight() const {return *itsweight;}
13 void setage(int age) {*itsage = age;}
14
15 private:
16 int *itsage;
17 int *itsweight;
18 };
19
20 cat::cat()
21 {
22 itsage = new int;
23 itsweight = new int;
24 *itsage = 5;
25 *itsweight = 9;
26 }
27
28 cat::cat(const cat & rhs) //通常用rhs來表示複製建構函式的引數
29 {
30 itsage = new int;
31 itsweight = new int;
32 *itsage = rhs.getage(); //public access
33 *itsweight = *(rhs.itsweight); //private access
34 }
35
36 cat::~cat()
37 {
38 delete itsage;
39 itsage = 0;
40 delete itsweight;
41 itsweight = 0;
42 }
43
44 int main()
45 {
46 cat frisky;
47 cout << frisky.getage() < 48 cout << frisky.getweight() < 49 cout << "nn";
50 frisky.setage(6);
51
52 cat boots(frisky);
53 cout << frisky.getage() << endl;
54 cout << frisky.getweight() < 55 cout << boots.getage() < 56 cout << boots.getweight() < 57 cout << "nn";
58
59 frisky.setage(7);
60 cout << frisky.getage() << endl;
61 cout << frisky.getweight() < 62 cout << boots.getage() < 63 cout << boots.getweight() < 64
65 return 0;
66 }
結果:
5
9


6
9
6
9


7
9
6
9

過載前置運算子
1 #include
2
3 using namespace std;
4
5 class counter
6 {
7 public:
8 counter();
9 ~counter() {}
10 int getitsval() const {return itsval;}
11 void setitsval(int x) {itsval = x;}
12 void increment() {++itsval;}
13 void operator++ () {++itsval;} //過載了operator++,
14
15 private:
16 int itsval;
17 };
18
19 counter::counter():itsval(0)
20 {}
21
22 int main()
23 {
24 counter i;
25 cout << i.getitsval() << endl;
26 i.increment();
27 cout << i.getitsval() << endl;
28 ++i;
29 cout << i.getitsval() << endl;
30
31 return 0;
32 }
結果:
0
1
2
利用 void operator++ () 語法進行過載++運算子。

繼承 protected保護型,使資料對於這個類和從這個類派生出來的類是可見的。
例子:
1 #include
2
3 using namespace std;
4
5 enum BREED {GOLDEN,CAIRN,OANDIE,SHETLAND,DOBERMAN,LAB};
6
7 class Mammal
8 {
9 public:
10 Mammal();
11 ~Mammal();
12
13 int getage() const {return itsage;}
14 void setage(int age) {itsage = age;}
15 int getweight() const {return itsweight;}
16 void setweight(int weight) {itsweight = weight;}
17
18 void speak() const {cout << "++++++++++++++++n";}
19 void sleep() const {cout << "----------------n";}
20
21 protected:
22 int itsage;
23 int itsweight;
24 };
25
26 class dog : public Mammal
27 {
28 public:
29 dog();
30 ~dog();
31
32 BREED getbreed() const {return itsbreed;}
33 void setbreed(BREED breed){itsbreed = breed;}
34
35 void wagtail() const {cout << "$$$$$$$$$$$n";}
36 void begforfood() const {cout << "~~~~~~~~n";}
37
38 private:
39 BREED itsbreed;
40 };
41
42 Mammal::Mammal():itsage(1),itsweight(5)
43 {
44 cout << "Mammal constructor...n";
45 }
46
47 Mammal::~Mammal()
48 {
49 cout << "Mammal destructor...n";
50 }
51
52 dog::dog():itsbreed(GOLDEN)
53 {
54 cout << "dog constructor...n";
55 }
56
57 dog::~dog()
58 {
59 cout << "dog destructor...n";
60 }
61
62 int main()
63 {
64 dog fido;
65 printf("---------------[1]---------n");
66 fido.speak();
67 printf("---------------[2]---------n");
68 fido.wagtail();
69 printf("---------------[3]---------n");
70 cout << fido.getage() << endl;
71 printf("---------------[4]---------n");
72
73 return 0;
74 }
結果:
Mammal constructor...
dog constructor...
---------------[1]---------
++++++++++++++++
---------------[2]---------
$$$$$$$$$$$
---------------[3]---------
1
---------------[4]---------
dog destructor...
Mammal destructor...

覆蓋函式:dog物件可以訪問Mammal類中的所有成員函式,也可以訪問dog類可能增加的任何成員函式,例如wagtail()。它還可以覆蓋一個基類函式。覆蓋函式意味著在派生類中改變基類函式的實現。當派生類用與基類的成員函式相同的返回值和簽名,但卻用新的實現方法建立一個函式時,就稱為覆蓋了該方法。
例子:
1 #include
2 using namespace std;
3
4 enum BREED{GOLDEN,CAIRN,DANDIE,SHETLAND,DOBERMAN,LAB};
5
6 class Mammal
7 {
8 public:
9 Mammal() {cout << "Mammal constructor...n";}
10 ~Mammal() {cout << "Mammal destructor...n";}
11
12 void speak() const {cout << "Mammal sound!n";}
13 void sleep() const {cout << "++++++++++++++n";}
14
15 protected:
16 int itsage;
17 int itsweight;
18 };
19
20 class dog:public Mammal
21 {
22 public:
23 dog(){cout << "dog constructor...n";}
24 ~dog(){cout << "dog destructor...n";}
25
26 void wagtail() const {cout << "tail wagging...n";}
27 void begforfood()const{cout << "begging for food...n";}
28 void speak() const {cout << "woof!n";}
29
30 private:
31 BREED itsbreed;
32 };
33
34 int main()
35 {
36 Mammal big;
37 dog fido;
38 big.speak();
39 fido.speak();
40
41 return 0;
42 }
結果:
Mammal constructor...
Mammal constructor...
dog constructor...
Mammal sound!
woof!
dog destructor...
Mammal destructor...
Mammal destructor...

從覆蓋方法中呼叫基方法
1 #include
2 using namespace std;
3
4 class Mammal
5 {
6 public:
7 void move() const {cout << "----------n";}
8 void move(int distance) const
9 {
10 cout << "[1]++++++++n";
11 cout << "[2]++++++++n";
12 }
13 protected:
14 int itsage;
15 int itsweight;
16 };
17
18 class dog:public Mammal
19 {
20 public:
21 void move() const;
22 };
23
24 void dog::move() const
25 {
26 cout << "#####n";
27 Mammal::move(3);
28 }
29
30 int main()
31 {
32 Mammal big;
33 dog fido;
34
35 big.move(2);
36 fido.Mammal::move();
37 fido.move();
38
39 return 0;
40 }
結果:
[1]++++++++
[2]++++++++
----------
#####
[1]++++++++
[2]++++++++

虛擬函式
例子:
1 #include
2 using namespace std;
3
4 class Mammal
5 {
6 public:
7 Mammal():itsage(1) {cout << "Mammal conn";}
8 virtual ~Mammal() {cout << "Mammal des";}
9 void move() const {cout << "Mammal move -----n";}
10 virtual void speak() const {cout << "Mammal speak!n";}
11 protected:
12 int itsage;
13 };
14
15 class dog:public Mammal
16 {
17 public:
18 dog() {cout << "dog conn";}
19 virtual ~dog() {cout << "dog desn"; }
20 void wagtail() {cout << "wagging tail...n";}
21 void speak() const {cout << "woooooooooooooofn";}//由於speak是虛擬函式,因此呼叫在dog中被覆蓋的speak函式
22 void move() const {cout << "dog moves 5555555555n";}
23 };
24
25 int main()
26 {
27 Mammal *pDog = new dog;
28 pDog->move();
29 pDog->speak();
30
31 return 0;
32 }
結果:
Mammal con
dog con
Mammal move -----
woooooooooooooof
虛擬函式只對指標和引用有效,按值傳遞不允許呼叫虛擬函式。類中一個函式時虛擬函式,那麼解構函式也應該是虛擬函式。派生類的解構函式會自動呼叫基類的解構函式,結果整個物件就會正確銷燬。
但建構函式不能是虛擬函式,也不存在虛複製建構函式

多型性
一段小程式:
1 #include
2 using namespace std;
3
4 class horse
5 {
6 public:
7 void gallop() {cout << "galloping...n";}
8 virtual void fly()
9 {
10 cout << "horses can't fly.n";
11 }
12 private:
13 int itsage;
14 };
15
16 class pegasus:public horse
17 {
18 public:
19 virtual void fly() {cout << "i can fly~~!n";}
20 };
21
22 const int num = 5;
23
24 int main()
25 {
26 horse *ranch[num];
27 horse *phorse;
28 int choice,i;
29 for(i = 0; i < num; i++)
30 {
31 cout << "(1)horse (2)pegasus : ";
32 cin >> choice;
33 if(choice == 2)
34 phorse = new pegasus;
35 else
36 phorse = new horse;
37 ranch[i] = phorse;
38 }
39
40 cout << "n";
41
42 for(i = 0; i < num; i++)
43 {
44 ranch[i]->fly();
45 delete ranch[i];
46 }
47
48 return 0;
49 }
結果:
(1)horse (2)pegasus : 2
(1)horse (2)pegasus : 1
(1)horse (2)pegasus : 2
(1)horse (2)pegasus : 2
(1)horse (2)pegasus : 1

i can fly~~!
horses can't fly.
i can fly~~!
i can fly~~!
horses can't fly.

多重繼承:
1 #include
2 using namespace std;
3
4 class horse
5 {
6 public:
7 horse()
8 {
9 cout << "horse constructor...n";
10 }
11 virtual ~horse()
12 {
13 cout << "horse destructor...n";
14 }
15 virtual void whinny() const
16 {
17 cout << "whinny...n";
18 }
19 private:
20 int itsage;
21 };
22
23 class bird
24 {
25 public:
26 bird()
27 {
28 cout << "bird constructor...n";
29 }
30 virtual ~bird()
31 {
32 cout << "bird destructor...n";
33 }
34 virtual void chirp() const
35 {
36 cout << "chirp...n";
37 }
38 virtual void fly() const
39 {
40 cout << "i can fly!";
41 }
42 private:
43 int itsage;
44 };
45
46 class pegasus:public horse,public bird
47 {
48 public:
49 void chirp() const
50 {
51 whinny();
52 }
53 pegasus()
54 {
55 cout << "pegasus constructor...n";
56 }
57 ~pegasus()
58 {
59 cout << "pegasus destructor...n";
60 }
61 };
62
63 const int NUM = 2;
64
65 int main()
66 {
67 horse *ranch[NUM];
68 bird *avi[NUM];
69 horse *pHorse;
70 bird *pBird;
71 int choice,i;
72 for(i = 0; i < NUM; i++)
73 {
74 cout << "1: Horse 2: pegasus :";
75 cin >> choice;
76 if(choice == 2)
77 pHorse = new pegasus;
78 else
79 pHorse = new horse;
80 ranch[i] = pHorse;
81 }
82
83 for(i = 0; i < NUM; i++)
84 {
85 cout << "1: bird 2: pegasus :";
86 cin >> choice;
87 if(choice ==2)
88 pBird = new pegasus;
89 else
90 pBird = new bird;
91 avi[i] = pBird;
92 }
93
94 cout << "n";
95 for(i = 0; i < NUM; i++)
96 {
97 cout << "nRanch[" << i << "]:";
98 ranch[i]->whinny();
99 delete ranch[i];
100 }
101
102 for(i = 0; i < NUM; i++)
103 {
104 cout << "naviary[" << i << "]:";
105 avi[i]->chirp();
106 avi[i]->fly();
107 delete avi[i];
108 }
109 return 0;
110 }
結果:
1: Horse 2: pegasus :1
horse constructor...
1: Horse 2: pegasus :2
horse constructor...
bird constructor...
pegasus constructor...
1: bird 2: pegasus :1
bird constructor...
1: bird 2: pegasus :2
horse constructor...
bird constructor...
pegasus constructor...


Ranch[0]:whinny...
horse destructor...

Ranch[1]:whinny...
pegasus destructor...
bird destructor...
horse destructor...

aviary[0]:chirp...
i can fly!bird destructor...

aviary[1]:whinny...
i can fly!pegasus destructor...
bird destructor...
horse destructor...

多重繼承物件中的建構函式
1 #include
2
3 using namespace std;
4
5 enum COLOR {red,green,blue,yellow,white,black,brown};
6
7 class horse
8 {
9 public:
10 horse(COLOR color, int height);
11 virtual ~horse()
12 {
13 cout << "horse destructor ...n";
14 }
15 virtual void whinny() const
16 {
17 cout << "whinny!...n";
18 }
19 virtual int getheight() const
20 {
21 return itsHeight;
22 }
23 virtual COLOR getcolor() const
24 {
25 return itsColor;
26 }
27 private:
28 int itsHeight;
29 COLOR itsColor;
30 };
31
32 horse::horse(COLOR color, int height):itsColor(color),itsHeight(height)
33 {
34 cout << "Horse constructor ...n";
35 }
36
37 class bird
38 {
39 public:
40 bird(COLOR color, bool migrates);
41 virtual ~bird()
42 {
43 cout << "bird destrutor ... n";
44 }
45 virtual void chirp() const
46 {
47 cout << "chirp ...n";
48 }
49 virtual void fly() const
50 {
51 cout << "i can fly!~~~~~~~~~~~~~~~~~n";
52 }
53 virtual COLOR getcolor() const
54 {
55 return itsColor;
56 }
57 virtual bool getmigration() const
58 {
59 return itsMigration;
60 }
61 private:
62 COLOR itsColor;
63 bool itsMigration;
64 };
65
66 bird::bird(COLOR color, bool migrates):itsColor(color),itsMigration(migrates)
67 {
68 cout << "bird constructor ... n";
69 }
70
71 class pegasus:public horse,public bird
72 {
73 public:
74 void chirp() const
75 {
76 whinny();
77 }
78 pegasus(COLOR,int,bool,long);
79 ~pegasus()
80 {
81 cout << "pegasus destructor ...n";
82 }
83 virtual long getnumberbelievers() const
84 {
85 return itsNumberBelievers;
86 }
87 private:
88 long itsNumberBelievers;
89 };
90
91 pegasus::pegasus(COLOR aColor,int height,bool migrates,long NumBelieve):horse(aColor,height),bird(aColor,migrates),itsNumberBeli
evers(NumBelieve)
92 {
93 cout << "pegasus constructor ...n";
94 }
95
96 int main()
97 {
98 pegasus *pPeg = new pegasus(red,5,true,10);
99 pPeg->fly();
100 pPeg->whinny();
101 cout << "n+++++++++ " << pPeg->getheight();
102 if(pPeg->getmigration())
103 cout << "[1]###n";
104 else
105 cout << "[2]###n";
106 cout << "n~~~~~ " << pPeg->getnumberbelievers();
107 delete pPeg;
108 return 0;
109 }
結果:
Horse constructor ...
bird constructor ...
pegasus constructor ...
i can fly!~~~~~~~~~~~~~~~~~
whinny!...

+++++++++ 5[1]###

~~~~~ 10pegasus destructor ...
bird destrutor ...
horse destructor ...

歧義解析:
如果在main中檢視getcolor函式獲得顏色,要注意兩個基類都有顏色
cout << pPeg->getcolor() <cout << pPeg->horse::getcolor() <

從共享基類中繼承
例子:
1 #include
2 using namespace std;
3
4 enum COLOR {red,green,blue,yellow,white,black,brown};
5
6 class animal
7 {
8 public:
9 animal(int);
10 virtual ~animal()
11 {
12 cout << "animal desn";
13 }
14 virtual int getage() const
15 {
16 return itsage;
17 }
18 virtual void setage(int age)
19 {
20 itsage = age;
21 }
22 private:
23 int itsage;
24 };
25
26 animal::animal(int age):itsage(age)
27 {
28 cout << "animal conn";
29 }
30
31 class horse:public animal
32 {
33 public:
34 horse(COLOR color,int height,int age);
35 virtual ~horse()
36 {
37 cout << "horse desn";
38 }
39 virtual void whinny() const
40 {
41 cout << "whinny!n";
42 }
43 virtual int getheight() const
44 {
45 return itsHeight;
46 }
47 virtual COLOR getcolor() const
48 {
49 return itsColor;
50 }
51 protected:
52 int itsHeight;
53 COLOR itsColor;
54 };
55
56 horse::horse(COLOR color,int height, int age):animal(age),itsColor(color),itsHeight(height)
57 {
58 cout << "horse conn";
59 }
60
61 class bird:public animal
62 {
63 public:
64 bird(COLOR color,bool migrates,int age);
65 virtual ~bird()
66 {
67 cout << "bird desn";
68 }
69 virtual void chirp() const
70 {
71 cout << "chirp!n";
72 }
73 virtual void fly() const
74 {
75 cout << "i can fly!n";
76 }
77 virtual COLOR getcolor() const
78 {
79 return itsColor;
80 }
81 virtual bool getmigration() const
82 {
83 return itsmigration;
84 }
85 protected:
86 COLOR itsColor;
87 bool itsmigration;
88 };
89
90 bird::bird(COLOR color,bool migrates,int age):animal(age),itsColor(color),itsmigration(migrates)
91 {
92 cout << "bird conn";
93 }
94
95 class pegasus:public horse,public bird
96 {
97 public:
98 void chirp() const
99 {
100 whinny();
101 }
102 pegasus(COLOR, int, bool, long, int);
103 virtual ~pegasus()
104 {
105 cout << "pegasus desn";
106 }
107 virtual long getnumberbelievers() const
108 {
109 return itsnumberbelievers;
110 }
111 virtual COLOR getcolor() const
112 {
113 return horse::itsColor;
114 }
115 virtual int getage() const
116 {
117 return bird::getage();
118 //return horse::getage();
119 }
120 private:
121 long itsnumberbelievers;
122 };
123
124 pegasus::pegasus(COLOR aColor,int height,bool migrates,long numbelieve,int age):horse(aColor,height,age),bird(aColor,migrates,ag
e),itsnumberbelievers(numbelieve)
125 {
126 cout << "pegasus conn";
127 }
128
129 int main()
130 {
131 pegasus *pPeg = new pegasus(yellow,5,true,10,3);
132 int age = pPeg->getage();
133 cout << "================" << age <134 delete pPeg;
135
136 return 0;
137 }
結果:
animal con
horse con
animal con
bird con
pegasus con
================3
pegasus des
bird des
animal des
horse des
animal des

虛繼承
在上個例子中,不想使用共享基類的兩個副本,而是隻想有一個共享基類
例子:
1 #include
2 using namespace std;
3
4 enum COLOR {red,green,blue,yellow,white,black,brown};
5
6 class animal
7 {
8 public:
9 animal(int);
10 virtual ~animal()
11 {
12 cout << "animal desn";
13 }
14 virtual int getage() const
15 {
16 return itsage;
17 }
18 virtual void setage(int age)
19 {
20 itsage = age;
21 }
22 private:
23 int itsage;
24 };
25
26 animal::animal(int age):itsage(age)
27 {
28 cout << "animal conn";
29 }
30
31 class horse: virtual public animal
32 {
33 public:
34 horse(COLOR color,int height,int age);
35 virtual ~horse()
36 {
37 cout << "horse desn";
38 }
39 virtual void whinny() const
40 {
41 cout << "whinny!n";
42 }
43 virtual int getheight() const
44 {
45 return itsHeight;
46 }
47 virtual COLOR getcolor() const
48 {
49 return itsColor;
50 }
51 protected:
52 int itsHeight;
53 COLOR itsColor;
54 };
55
56 horse::horse(COLOR color,int height, int age):animal(age),itsColor(color),itsHeight(height)
57 {
58 cout << "horse conn";
59 }
60
61 class bird:virtual public animal
62 {
63 public:
64 bird(COLOR color,bool migrates,int age);
65 virtual ~bird()
66 {
67 cout << "bird desn";
68 }
69 virtual void chirp() const
70 {
71 cout << "chirp!n";
72 }
73 virtual void fly() const
74 {
75 cout << "i can fly!n";
76 }
77 virtual COLOR getcolor() const
78 {
79 return itsColor;
80 }
81 virtual bool getmigration() const
82 {
83 return itsmigration;
84 }
85 protected:
86 COLOR itsColor;
87 bool itsmigration;
88 };
89
90 bird::bird(COLOR color,bool migrates,int age):animal(age),itsColor(color),itsmigration(migrates)
91 {
92 cout << "bird conn";
93 }
94
95 class pegasus:public horse,public bird
96 {
97 public:
98 void chirp() const
99 {
100 whinny();
101 }
102 pegasus(COLOR, int, bool, long, int);
103 virtual ~pegasus()
104 {
105 cout << "pegasus desn";
106 }
107 virtual long getnumberbelievers() const
108 {
109 return itsnumberbelievers;
110 }
111 virtual COLOR getcolor() const
112 {
113 return horse::itsColor;
114 }
115 virtual int getage() const
116 {
117 return bird::getage();
118 //return horse::getage();
119 }
120 private:
121 long itsnumberbelievers;
122 };
123
124 pegasus::pegasus(COLOR aColor,int height,bool migrates,long numbelieve,int age):horse(aColor,height,age),bird(aColor,migrates,ag
e),animal(age*2),itsnumberbelievers(numbelieve)
125 {
126 cout << "pegasus conn";
127 }
128
129 int main()
130 {
131 pegasus *pPeg = new pegasus(yellow,5,true,10,3);
132 int age = pPeg->getage();
133 cout << "================" << age <134 delete pPeg;
135
136 return 0;
137 }

結果:
animal con
horse con
bird con
pegasus con
================6
pegasus des
bird des
horse des
animal des

抽象型別,例子:
1 #include
2 using namespace std;
3
4 class shape
5 {
6 public:
7 shape(){}
8 virtual ~shape(){}
9 virtual long getarea(){return -1;}
10 virtual long getperim(){return -1;}
11 virtual void draw(){}
12 private:
13 };
14
15 class circle:public shape
16 {
17 public:
18 circle(int radius):itsradius(radius){}
19 ~circle(){}
20 long getarea () {return 3*itsradius * itsradius;}
21 long getperim(){return 6*itsradius;}
22 void draw();
23 private:
24 int itsradius;
25 int itscircumference;
26 };
27
28 void circle::draw()
29 {
30 cout << "circle drawn";
31 }
32
33 class rectangle:public shape
34 {
35 public:
36 rectangle(int len, int width):itslength(len),itswidth(width) {}
37 virtual ~rectangle(){}
38 virtual long getarea(){return itslength*itswidth;}
39 virtual long getperim(){return 2*itslength + 2*itswidth;}
40 virtual int getlength(){return itslength;}
41 virtual int getwidth(){return itswidth;}
42 virtual void draw();
43 private:
44 int itswidth;
45 int itslength;
46 };
47
48 void rectangle::draw()
49 {
50 for(int i = 0; i < itslength; i++)
51 {
52 for(int j = 0; j < itswidth; j++)
53 cout << " x";
54 cout << "n";
55 }
56 }
57
58 class square:public rectangle
59 {
60 public:
61 square(int len);
62 square(int len, int width);
63 ~square(){}
64 long getperim()
65 {
66 return 4*getlength();
67 }
68 };
69
70 square::square(int len):rectangle(len,len)
71 {}
72
73 square::square(int len, int width):rectangle(len, width)
74 {
75 if(getlength() != getwidth())
76 cout << "error ^_^n";
77 }
78
79 int main()
80 {
81 int choice;
82 bool fquit = false;
83 shape *sp;
84
85 while(!fquit)
86 {
87 cout << "1:circle 2:rectangle 3:square 0:quit:";
88 cin >> choice;
89
90 switch(choice)
91 {
92 case 0:
93 fquit = true;
94 break;
95 case 1:
96 sp = new circle(5);
97 break;
98 case 2:
99 sp = new rectangle(4,6);
100 break;
101 case 3:
102 sp = new square(5);
103 break;
104 default:
105 cout << "please enter a number: ";
106 continue;
107 break;
108 }
109 if(!fquit)
110 sp->draw();
111 delete sp;
112 sp = 0;
113 cout << "n";
114 }
115 return 0;
116 }
結果:
1:circle 2:rectangle 3:square 0:quit:1
circle draw

1:circle 2:rectangle 3:square 0:quit:2
x x x x x x
x x x x x x
x x x x x x
x x x x x x

1:circle 2:rectangle 3:square 0:quit:3
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x

1:circle 2:rectangle 3:square 0:quit:4
please enter a number: 1:circle 2:rectangle 3:square 0:quit:0

純虛擬函式
一個虛擬函式初始化為0程式設計了純虛擬函式
virtual void Draw()=0;
把一個純虛擬函式放在你的類中對你的類的客戶來說意味著兩件事:
1:不要從這個類中建立物件,要從其中派生
2:確信覆蓋了純虛擬函式。
上面的程式
將shape改寫
class shape
{
public:
shape(){}
~shape(){}
virtual long getarea() = 0;
virtual long getperim() = 0;
virtual void draw() = 0;
private:
};
重新執行程式,程式執行不受影響,唯一區別是現在不能建立一個shape類的物件。

實現純虛擬函式,只要其中任何一個被宣告為純虛擬函式,那麼這個類就是一個ADT
例子:
1 #include
2 using namespace std;
3
4 class shape
5 {
6 public:
7 shape(){}
8 virtual ~shape(){}
9
10 virtual long getarea() = 0;
11 virtual long getperim() = 0;
12 virtual void draw() = 0;
13 private:
14 };
15
16 void shape::draw()
17 {
18 cout << "abstract drawing !!!!!!!!!!!!!!n";
19 }
20
21 class circle:public shape
22 {
23 public:
24 circle(int radius):itsradius(radius){}
25 virtual ~circle(){}
26 long getarea () {return 3*itsradius * itsradius;}
27 long getperim(){return 9*itsradius;}
28 void draw();
29 private:
30 int itsradius;
31 int itscircumference;
32 };
33
34 void circle::draw()
35 {
36 cout << "circle drawn";
37 shape::draw();
38 }
39
40 class rectangle:public shape
41 {
42 public:
43 rectangle(int len, int width):itslength(len),itswidth(width) {}
44 virtual ~rectangle(){}
45 long getarea(){return itslength*itswidth;}
46 long getperim(){return 2*itslength + 2*itswidth;}
47 virtual int getlength(){return itslength;}
48 virtual int getwidth(){return itswidth;}
49 void draw();
50 private:
51 int itswidth;
52 int itslength;
53 };
54
55 void rectangle::draw()
56 {
57 for(int i = 0; i < itslength; i++)
58 {
59 for(int j = 0; j < itswidth; j++)
60 cout << " x";
61 cout << "n";
62 }
63 shape::draw();
64 }
65
66 class square:public rectangle
67 {
68 public:
69 square(int len);
70 square(int len, int width);
71 virtual ~square(){}
72 long getperim()
73 {
74 return 4*getlength();
75 }
76 };
77
78 square::square(int len):rectangle(len,len)
79 {}
80
81 square::square(int len, int width):rectangle(len, width)
82 {
83 if(getlength() != getwidth())
84 cout << "error ^_^n";
85 }
86
87 int main()
88 {
89 int choice;
90 bool fquit = false;
91 shape *sp;
92
93 while(!fquit)
94 {
95 cout << "1:circle 2:rectangle 3:square 0:quit:";
96 cin >> choice;
97
98 switch(choice)
99 {
100 case 0:
101 fquit = true;
102 break;
103 case 1:
104 sp = new circle(5);
105 break;
106 case 2:
107 sp = new rectangle(4,6);
108 break;
109 case 3:
110 sp = new square(5);
111 break;
112 default:
113 cout << "please enter a number: ";
114 continue;
115 break;
116 }
117 if(!fquit)
118 sp->draw();
119 delete sp;
120 sp = 0;
121 cout << "n";
122 }
123 return 0;
124 }
結果:
1:circle 2:rectangle 3:square 0:quit:1
circle draw
abstract drawing !!!!!!!!!!!!!!

1:circle 2:rectangle 3:square 0:quit:2
x x x x x x
x x x x x x
x x x x x x
x x x x x x
abstract drawing !!!!!!!!!!!!!!

1:circle 2:rectangle 3:square 0:quit:3
x x x x x
x x x x x
x x x x x
x x x x x
x x x x x
abstract drawing !!!!!!!!!!!!!!

1:circle 2:rectangle 3:square 0:quit:4
please enter a number: 1:circle 2:rectangle 3:square 0:quit:0

circle和rectangle都覆蓋了draw(),兩者都是連結到了基方法,利用了基類中的共享功能。

從其他的ADT中派生ADT
例子:
1 #include
2 using namespace std;
3
4 enum COLOR {red,green,blue,yellow,white,black,brown};
5
6 class animal
7 {
8 public:
9 animal(int);
10 virtual ~animal(){cout << "animal desn";}
11 virtual int getage() const {return itsage;}
12 virtual void setage(int age){itsage = age;}
13
14 virtual void sleep() const = 0;
15 virtual void eat() const = 0;
16 virtual void reproduce() const = 0;
17 virtual void move() const = 0;
18 virtual void speak() const = 0;
19 private:
20 int itsage;
21 };
22
23 animal::animal(int age):itsage(age)
24 {
25 cout << "animal conn";
26 }
27
28 class mammal:public animal
29 {
30 public:
31 mammal(int age):animal(age)
32 {
33 cout << "Mammal conn";
34 }
35 virtual ~mammal()
36 {
37 cout << "Mammal desn";
38 }
39 virtual void reproduce() const
40 {
41 cout << "Mammal reproductionn";
42 }
43 };
44
45 class fish:public animal
46 {
47 public:
48 fish(int age):animal(age)
49 {
50 cout << "fish conn";
51 }
52 virtual ~fish()
53 {
54 cout << "fish desn";
55 }
56 virtual void sleep() const
57 {
58 cout << "fish snoringn";
59 }
60 virtual void eat() const
61 {
62 cout << "fish feedingn";
63 }
64 virtual void reproduce() const
65 {
66 cout << "fish laying eggsn";
67 }
68 virtual void move() const
69 {
70 cout << "fish swimmingn";
71 }
72 virtual void speak() const
73 {
74 }
75 };
76
77 class horse:public mammal
78 {
79 public:
80 horse(int age,COLOR color):mammal(age),itscolor(color)
81 {
82 cout << "horse conn";
83 }
84 virtual ~horse()
85 {
86 cout << "horse desn";
87 }
88 virtual void speak() const
89 {
90 cout << "horse speak";
91 }
92 virtual COLOR getitscolor()const
93 {
94 return itscolor;
95 }
96 virtual void sleep()const
97 {
98 cout << "horse sleepn";
99 }
100 virtual void eat() const
101 {
102 cout << "horse eatn";
103 }
104 virtual void move() const
105 {
106 cout << "horse moven";
107 }
108 protected:
109 COLOR itscolor;
110 };
111
112 class dog:public mammal
113 {
114 public:
115 dog(int age, COLOR color):mammal(age),itscolor(color)
116 {
117 cout << "dog conn";
118 }
119 virtual ~dog(){cout << "dog desn";}
120 virtual void speak() const
121 {
122 cout << "dog speakn";
123 }
124 virtual void sleep() const
125 {
126 cout << "dog sleepn";
127 }
128 virtual void eat() const
129 {
130 cout << "dog eatn";
131 }
132 virtual void move() const
133 {
134 cout << "dog moven";
135 }
136 virtual void reproduce() const
137 {
138 cout << "dog reproducen";
139 }
140 protected:
141 COLOR itscolor;
142 };
143
144 int main()
145 {
146 animal *panimal=0;
147 int choice;
148 bool fquit=false;
149
150 while(1)
151 {
152 cout << "1: dog 2:horse 3:fish 0:quit :";
153 cin >> choice;
154
155 switch (choice)
156 {
157 case 1:
158 panimal = new dog(5,brown);
159 break;
160 case 2:
161 panimal = new horse(4,black);
162 break;
163 case 3:
164 panimal = new fish(5);
165 break;
166 default:
167 fquit = true;
168 break;
169 }
170 if(fquit)
171 break;
172
173 panimal->speak();
174 panimal->eat();
175 panimal->reproduce();
176 panimal->move();
177 panimal->sleep();
178
179 delete panimal;
180
181 cout << "n";
182 }
183 return 0;
184 }
185
結果:
1: dog 2:horse 3:fish 0:quit :1
animal con
Mammal con
dog con
dog speak
dog eat
dog reproduce
dog move
dog sleep
dog des
Mammal des
animal des

1: dog 2:horse 3:fish 0:quit :2
animal con
Mammal con
horse con
horse speakhorse eat
Mammal reproduction
horse move
horse sleep
horse des
Mammal des
animal des

1: dog 2:horse 3:fish 0:quit :3
animal con
fish con
fish feeding
fish laying eggs
fish swimming
fish snoring
fish des
animal des

1: dog 2:horse 3:fish 0:quit :4

mammal從animal派生,但覆蓋了reproduce()方法,為所有哺乳動物提供了相同的繁殖方式,fish必須覆蓋reproduce(),因為它是直接從animal類中派生的,不能利用哺乳動物的繁殖方式。mammal類不再必須覆蓋reproduce()方法。fish、horse和dog均覆蓋了剩餘的純虛擬函式,這樣他們那一型別的物件就可以例項化了,試圖例項化animal和mammal會產生編譯錯誤,因為他們都是抽象資料型別。

靜態成員變數
靜態成員變數在一個類的所有物件中是共享的。可以把靜態成員變數看作屬於類的而不是屬於物件的。
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat(int age):itsage(age)
9 {
10 howmanycats++;
11 }
12 virtual ~cat()
13 {
14 howmanycats--;
15 }
16 virtual int getage()
17 {
18 return itsage;
19 }
20 virtual void setage(int age)
21 {
22 itsage = age;
23 }
24 static int howmanycats;
25 private:
26 int itsage;
27 };
28
29 int cat::howmanycats = 0;
30
31 int main()
32 {
33 const int maxcats = 5;
34 int i;
35 cat *cathouse[maxcats];
36
37 for(i = 0; i < maxcats; i++)
38 cathouse[i] = new cat(i);
39
40 for(i = 0; i < maxcats; i++)
41 {
42 cout << cat::howmanycats << endl;
43 cout << cathouse[i]->getage() << endl;
44
45 delete cathouse[i];
46 cathouse[i] = 0;
47 }
48 return 0;
49 }
結果:
5
0
4
1
3
2
2
3
1
4

永遠透過一個cat例項來訪問這些資料,那麼最好是這個成員變數和其他成員變數一起成為私有變數,並且提供一個公有訪問函式。另一方面,如果你想在不必使用cat物件的情況下直接訪問這個資料,可以有兩種方法:把它變成公有變數,或提供一個靜態成員函式。

訪問沒有物件的靜態成員
例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat(int age):itsage(age)
9 {
10 howmanycats++;
11 }
12 virtual ~cat()
13 {
14 howmanycats--;
15 }
16 virtual int getage()
17 {
18 return itsage;
19 }
20 virtual void setage(int age)
21 {
22 itsage = age;
23 }
24 static int howmanycats;
25 private:
26 int itsage;
27 };
28
29 int cat::howmanycats = 0;
30
31 void fun();
32
33 int main()
34 {
35 const int maxcats = 3;
36 int i;
37 cat *cathouse[maxcats];
38
39 for(i = 0; i < maxcats; i++)
40 {
41 cathouse[i] = new cat(i);
42 fun();
43 }
44
45 for(i = 0; i < maxcats; i++)
46 {
47 delete cathouse[i];
48 fun();
49 }
50 return 0;
51 }
52
53 void fun()
54 {
55 cout << cat::howmanycats << endl;
56 }
結果:
1
2
3
2
1
0

用非靜態成員函式訪問靜態成員
例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat(int age):itsage(age)
9 {
10 howmanycats++;
11 }
12 virtual ~cat()
13 {
14 howmanycats--;
15 }
16 virtual int getage()
17 {
18 return itsage;
19 }
20 virtual void setage(int age)
21 {
22 itsage = age;
23 }
24 virtual int gethowmany()
25 {
26 return howmanycats;
27 }
28 private:
29 static int howmanycats;
30 int itsage;
31 };
32
33 int cat::howmanycats = 0;
34
35 int main()
36 {
37 const int maxcats = 3;
38 int i;
39 cat *cathouse[maxcats];
40
41 for(i = 0; i < maxcats; i++)
42 {
43 cathouse[i] = new cat(i);
44 }
45
46 for(i = 0; i < maxcats; i++)
47 {
48 cout << cathouse[i]->gethowmany() << endl;
49 delete cathouse[i];
50 cathouse[i] = 0;
51 }
52 return 0;
53 }
結果:
3
2
1

必須用靜態成員變數來在一個類的所有例項間共享資料。如果相對靜態成員變數的訪問,則必須把他們宣告為保護型或私有型。不應該用靜態成員變數去存放某一個物件的資料,靜態成員資料是在這個類的所有物件間共享的。

靜態成員函式
例子:
1 #include
2
3 using namespace std;
4
5 class cat
6 {
7 public:
8 cat(int age):itsage(age)
9 {
10 howmanycats++;
11 }
12 virtual ~cat()
13 {
14 howmanycats--;
15 }
16 virtual int getage()
17 {
18 return itsage;
19 }
20 virtual void setage(int age)
21 {
22 itsage = age;
23 }
24 static int gethowmany()
25 {
26 return howmanycats;
27 }
28 private:
29 int itsage;
30 static int howmanycats;//宣告為私有訪問
31 };
32
33 int cat::howmanycats = 0;
34
35 void tel();
36
37 int main()
38 {
39 const int max = 5;
40 cat *cathouse[max];
41 int i;
42 for(i = 0; i < max; i++)
43 {
44 cathouse[i] = new cat(i);
45 tel();
46 }
47
48 for(i = 0; i < max; i++)
49 {
50 delete cathouse[i];
51 tel();
52 }
53 return 0;
54 }
55
56 void tel()
57 {
58 cout << cat::gethowmany() << endl;
59 }
結果:
1
2
3
4
5
4
3
2
1
0
由於gethowmany()是公有的,因此它可以由任何一個函式訪問,又由於它是靜態的,因此不必有一個cat型物件來呼叫它。
靜態成員函式沒有this指標,因此他們不能宣告為const。還由於成員資料變數在成員函式內是透過this指標來訪問的,因此靜態成員函式不能訪問任何非靜態成員變數!
就像呼叫其他成員函式一樣,你可以透過在這個類的某個物件中呼叫靜態成員函式來訪問靜態成員函式。或者你可不必採用完全限定類和物件名的物件來呼叫靜態成員函式。

函式指標
例子
1 #include
2 using namespace std;
3
4 void square(int&,int&);
5 void cube(int&,int&);
6 void swap(int&,int&);
7 void getvals(int&,int&);
8 void printvals(int,int);
9
10 int main()
11 {
12 void (* pfunc)(int&,int&);
13 bool fquit = false;
14
15 int valone = 1, valtwo = 2;
16 int choice;
17
18 while(fquit == false)
19 {
20 cout << "0:quit 1:change values 2:square 3:cube 4:swap: ";
21 cin >> choice;
22 switch(choice)
23 {
24 case 1: pfunc = getvals; break;
25 case 2: pfunc = square; break;
26 case 3: pfunc = cube; break;
27 case 4: pfunc = swap; break;
28 default: fquit = true; break;
29 }
30
31 if(fquit)
32 break;
33
34 printvals(valone,valtwo);
35 pfunc(valone,valtwo);
36 printvals(valone,valtwo);
37 }
38 return 0;
39 }
40
41 void printvals(int x, int y)
42 {
43 cout << "x: " << x << "y: " << y << endl;
44 }
45
46 void square(int& rx, int& ry)
47 {
48 rx *= rx;
49 ry *= ry;
50 }
51
52 void cube(int& rx, int& ry)
53 {
54 int tmp;
55 tmp = rx;
56 rx *= rx;
57 rx = rx*tmp;
58
59 tmp = ry;
60 ry *= ry;
61 ry = ry*tmp;
62 }
63
64 void swap(int& rx, int& ry)
65 {
66 int tmp;
67 tmp = rx;
68 rx = ry;
69 ry = tmp;
70 }
71
72 void getvals(int& rx, int& ry)
73 {
74 cout << "new value for valone:";
75 cin >> rx;
76 cout << "new value for valtwo:";
77 cin >> ry;
78
79 }
結果:
0:quit 1:change values 2:square 3:cube 4:swap: 1
x: 1y: 2
new value for valone:5
new value for valtwo:6
x: 5y: 6
0:quit 1:change values 2:square 3:cube 4:swap: 2
x: 5y: 6
x: 25y: 36
0:quit 1:change values 2:square 3:cube 4:swap: 3
x: 25y: 36
x: 15625y: 46656
0:quit 1:change values 2:square 3:cube 4:swap: 4
x: 15625y: 46656
x: 46656y: 15625
0:quit 1:change values 2:square 3:cube 4:swap: 0

pFunc(x) <=> (* pFunc)(x) 前一種是後一種的簡化形式

函式指標陣列
例子:
1 #include
2 using na

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23168012/viewspace-1047132/,如需轉載,請註明出處,否則將追究法律責任。

相關文章