在C語言裏可用一個結構體來描述一種類型,如描述學生信息:
typedef struct {
char name[20];
int age;
int id;
}student_t;
如有三個學生,則:
student_t a, b, c;
通常情況下,用變量成員來描述類型的屬性,但是類型的行爲特徵應用函數來描述.在結構體只能加入函數指針變量成員來描述.
typedef struct {
char name[20];
int age;
int id;
void (*study)(intwhat);
void (*eat)(intwhat);
}student_t;
結構使用起來時比較麻煩,創建一個對象都需要初始化對象的函數指針變量成員.
而且,在結構體裏每個成員沒有分權限來限制訪問的,無法保證一些數據的完整性.
C++針對c的結構體引入類:
類裏面可以直接實現函數成員。
類裏面的成員可分權限:private protected public
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student { // Student聲明後,直接使用Student就是表示類型
7 public: //聲明以下成員都是public的權限
8 string name; //注意:這裏僅僅是定義這個類型有哪些成員,並沒有分配具體的空間,所以這裏的成員不能賦初始值
9 int id;
10 int age;
11
12 voidstudy(int what) {
13 cout <<"study " << what << endl;
14 }
15
16 void eat(intwhat) {
17 cout <<"eat " << what << endl;
18 }
19 };
20
21 int main(void)
22 {
23 Student a,b; //創建對象a和b,每個對象都有自己的屬性成員,但函數成員是共用的(通過查看對象的大小可知).函數成員裏不能寫死針對某個對象的操作,只寫要使用的成員名即可。
24
25 a.eat(888);
26 return 0;
27 }
public權限的成員,只要通過類的對象或者指向對象的指針變量都可以訪問.
private權限的成員,只能在類的內部或者友員訪問.如需改變類對象裏的private權限成員的值時,應通過public的函數成員來改變. private成員就是不希望被直接訪問的,訪問也只能通過public函數成員來訪問。
所以我們可以把一些數據隱藏起來,只在內部處理,別人無需訪問,這就是封裝。
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student {
7 private:
8 string name;
9 int id;
10 int age;
11
12 public:
13 voidset_name(string n) {
14 name =n;
15 }
16
17 voidstudy(int what) {
18 cout <<name << " study " << what << endl;
19 }
20
21 };
22
23 int main(void)
24 {
25 Student a;
26
27 a.set_name("hehe");
28 a.study(23);
29
30
31 return 0;
32 }
私有成員也可以通過設置友員關係來訪問,但這種方式破壞了封裝性,儘量不要用.
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student {
7 private:
8 string name;
9 int id;
10 int age;
11
12 public:
13 voidstudy(int what) {
14 cout <<name << " study " << what << endl;
15 }
16 friend intmain(void); //聲明main函數是Student類型的朋友
17 // friend classxx;
18 };
19
20 int main(void)
21 {
22 Student a;
23
24 a.name ="lilei";
25 a.study(23);
26
27
28 return 0;
29 }
protected權限的成員,具有private的權限外,還可以讓子類對象訪問(後面再具體實現).
c++類裏還可以有構造函數,析構函數。
構造函數在創建對象時自動被調用的,可用於初始對象裏的屬性成員的值
析構函數在回收對象時自動被調用的, 可用於對象回收前所需作的事情.
通常情況下構造函數成員是public的權限,某些場合可以是private的權限
析構函數都是public的權限
構造函數名與類名完全一致,沒有返回值,連void返回類型也不能寫。構造函數可重載.
析構函數名與類名一樣(前面多一個”~”符號),沒有返回值,析構函數不可重載.
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student {
7 public:
8 Student() {
9 cout <<"student init" << endl;
10 }
11 ~Student() {
12 cout <<"student exit" << endl;
13 }
14 };
15
16 int main(void)
17 {
18 Student a;//如果是動態創建的對象需調用delete回收纔會觸發析構函數
19
20 cout <<"after object created" << endl;
21
22 return 0;
23 }
編譯執行後輸出:
[root@localhost06class]# ./a.out
student init
after object created
student exit
面試題,現有代碼如下:
int main(void)
{
cout <<“hello” << endl;
return 0;
}
要求不能改動main函數裏的代碼,實現在”hello”輸出前先輸出”nono”.
實現方法:創建一個全局類對象,觸發類的構造函數,構造函數裏輸出”nono”.
當自定義一個類型時,如沒有實現構造函數,編譯器會自動分配一個空的構造函數。
如果有實現構造函數,編譯器就不會再分配空的構造函數了.
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student {
7 private:
8 string name;
9
10 public:
11 Student(string n) {
12 name =n;
13 }
14
15 voidstudy(string what) {
16 cout <<name << " study " << what << endl;
17 }
18 };
19
20 int main(void)
21 {
22 Student a; //這裏創建對象,需調用Student::Student()構造函數.通過錯誤信息也可以得知一個類也是一個名稱空間.也可以得知,創建對象生成的代碼裏會有類構造函數的調用.
//c++裏調用哪個函數,除了函數名以外,與函數參數個數,類型有關.
23
24
25 return 0;
26 }
編譯輸出:
[root@localhost06class]# g++ 04contructor.cpp
04contructor.cpp: Infunction ‘int main()’:
04contructor.cpp:22:10:error: no matching function for call to ‘Student::Student()’
Student a;
^
04contructor.cpp:22:10:note: candidates are:
04contructor.cpp:11:2:note: Student::Student(std::string)
Student(string n){
^
04contructor.cpp:11:2:note: candidate expects 1 argument, 0 provided
04contructor.cpp:6:7:note: Student::Student(const Student&)
class Student {
^
04contructor.cpp:6:7:note: candidate expects 1 argument, 0 provided
可修改爲:
1
2 #include<iostream>
3
4 using namespacestd;
5
6 class Student {
7 private:
8 string name;
9
10 public:
11 Student(string n);
12 voidstudy(string what);
13 };
14
15 int main(void)
16 {
17 Studenta("superman"); // Student::Student(string)
18
19 a.study("Chinese");
20 return 0;
21 }
22
23Student::Student(string n)
24 {
25 name = n;
26 }
27
28 voidStudent::study(string what)
29 {
30 cout <<name << " study " << what << endl;
31 }
32
把雙向循環鏈表封裝成隊列的例子.
1
2 #include<iostream>
3
4 using namespacestd;
5
6//定義節點類型,隊列裏裝載多個節點對象
7 class Node {
8 public:
9 void *data;//裝數據的地址
10 Node *prev,*next;
11
12 Node(Node*n1 = NULL, Node *n2 = NULL) {
13 //創建對象時,兩個指針初始化爲傳進來的值,如不傳則設NULL
14 prev =n1;
15 next =n2;
16 }
17 };
18
19 //定義對列類型
20 class MyQueue {
21 private:
22 Node *head;//鏈表頭節點,只在內部使用
23
24 public:
25 MyQueue();
26 ~MyQueue();
27
28 intenqueue(void *data); //隊列的入隊函數
29 void*dequeue(); //隊列的出隊函數
30 };
31
32 int main(void)
33 {
34 MyQueue a,b; //每個對象就是一個隊列,不同的隊列可裝載不同類型的數據.重用起來就很方便了.
35 int *p;
36
37 a.enqueue(new int(22));
38 a.enqueue(new int(33));
39 a.enqueue(new int(44));
40 a.enqueue(new int(55));
41
42
43 while (p =(int *)a.dequeue())
44 cout <<*p << endl;
45
46
47
48 return 0;
49 }
50
51 void*MyQueue::dequeue()
52 {
53 Node *n;
54 void *data;
55
56 //把鏈表頭節點移除出隊列,交返回數據的地址
57 if(head->next == head)
58 returnNULL; //鏈表裏沒有節點
59
60 n =head->next;
61
62 head->next= n->next;
63 n->next->prev = head;
64 data =n->data;
65 delete n;
66 return data;
67 }
68
69 intMyQueue::enqueue(void *data)
70 {
71 Node *n;
72 //創建一個鏈表的節點對象,初始化後加入鏈表的尾部
73
74 n = newNode;
75 if (NULL ==n)
76 return-1;
77 n->data =data;
78 n->next =head;
79 n->prev =head->prev;
80
81 head->prev->next = n;
82 head->prev= n;
83 return 0;
84 }
85
86
87MyQueue::MyQueue()
88 {
89 //初始化鏈表頭節點,讓頭節點的prev,next指針指向自己本身
90 head = newNode;
91
92 head->prev= head;
93 head->next= head;
94 }
95
96
97MyQueue::~MyQueue()
98 {
99 Node *tmp,*tmp2;
100 //隊列回收前,把所有鏈表的節點空間回收
101 for (tmp =head->next; tmp != head;)
102 {
103 tmp->prev->next = tmp->next;
104 tmp->next->prev = tmp->prev;
105 tmp2 =tmp->next;
106 delete(char *)tmp->data;
107 deletetmp;
108 tmp =tmp2;
109 }
110
111 delete head;
112 }
總結下C++的class比C的struct方便的特點:
1.class的成員可分成不同權限,可控制哪些成員是被別人訪問的,哪些成員僅僅是內部使用.
struct的成員沒有分權限的,只可以訪問.
2.class可以直接寫函數成員,這樣更加直觀地描述一種類型包括它的行爲.
struct不可以直接寫函數成員,只可以寫函數指針成員,而且在使用函數指針成員前必須初始化指向一個有效的函數.
3.class裏的函數成員的參數在使用類內部的屬性成員時,不需要傳遞。在函數成員裏可以直接訪問類內部的屬性成員.
4.class還有構造函數與析構函數,初始化工作與回收前的工作都會自動觸發.