前提摘要
C++與C語言的最大差別就是在於物件導向的有無,在C語言時期的時候是運用函式導向,C語言有struct(結構)類似於C++的物件導向,但是struct僅擁有記憶體的存取的功能,並無運算資料的能力,所以C++的物件導向解決了這項問題,C++的物件導向擁有「資料成員」和「成員函式」,資料成員就是所謂的物件,提供記憶體給變數存取資料,而成員函式擁有運算資料的能力,因此C++的類別(class)就取代了C的結構(struct)。 ## 概述 首先要先了解什麼是類別,我這邊引用許裕永老師教學裡說的一段介紹文字,「類別就是一個製作說明書,材料是記憶體,配置出來的記憶體叫物件,但就程式語法來說,類別就是一個型別。」這段話清楚的表示出什麼是類別。
接著我們再來熟悉一下類別中有什麼,一個類別裡可以有「物件資料成員」、「物件成員函式」、「建構函式(建構子)」,大致上為這三個,的確還有其他種,但我大致上認為這三種最為重要。
在class裡用存取標籤 (access label) 來區分成員 (member) 的權限,而存取標籤有三種,public、private、protected,public的成員可以給所有物件在所有地方去呼叫,而private只能在class裡呼叫,protected 成員的使用範圍與 private 成員相同,而他們最大的差別是private裡的成員不可以被繼承,而protected裡的成員可以被繼承。 $$$$
public
故名思義,大眾,就是說在public的成員裡是可以被所有物件呼叫,以下為一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using namespace std;
class student{
public:
float weight;
float height;
float bmi(){
height /= 100;
return weight/(height*height);
}
};
int main(){
student max;
cin >> max.weight >> max.height;
cout << max.bmi();
return 0;
}
private
顧名思義,隱私,在private裡的成員只能被class裡面的成員呼叫,若被class外的物件呼叫會出現error,以下為使用private的例子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using namespace std;
class student{
private:
float weight = 70;
float height = 170;
public:
float bmi(){
height /= 100;
return weight/(height*height);
}
};
int main(){
student max;
cout << max.bmi() << endl;
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
class student{
private:
float weight;
float height;
public:
float bmi(){
height /= 100;
return weight/(height*height);
}
void change_value(float w,float h){
weight = w;
height = h;
}
};
int main(){
student max;
max.change_value(70,170);
cout << max.bmi() << endl;
return 0;
}
物件指標
首先先進行宣告,這邊要注意的是,我們宣告的是一個指標,和上面我們的宣告不一樣,我們上面宣告的是直接宣告一個物件,此時即有一群記憶體空間,而這邊如果要達到同樣目標,需new一個記憶體給它,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using namespace std;
class circle{
public:
int radius;
int height;
double girth;
double area;
double volume;
double get_girth(){
return radius*2*3.14;
}
};
int main(){
circle *pointer_one;
circle *pointer_two = new circle;
pointer_two->area = 100;
cout << pointer_two << endl;//output = 0x10050d5f0
if(pointer_one == nullptr) cout << "NULL" << endl;//output = NULL
cout << pointer_one << endl;//output = 0x0
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using namespace std;
class circle{
public:
int radius;
int height;
double girth;
double area;
double volume;
double get_girth(){
return radius*2*3.14;
}
};
int main(){
circle *pointer_one = new circle;
circle *pointer_two = new circle;
//不想要pointer_two的記憶體位置了
delete pointer_two;
pointer_two = pointer_one;
cout << pointer_one << endl;//output = 0x10504fad0
cout << pointer_two << endl;//output = 0x10504fad0
return 0;
}
物件指標當參數
今天如果會指標後我們在將物件傳入函式時就不用再讓函式複製一份資料,造成記憶體的浪費。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using namespace std;
class circle{
private:
double girth;
double area;
double volume;
public:
int radius;
int height;
bool cmp(circle * c1){
return c1->radius > 10 ? true : false;
}
};
int main(){
circle *c1 = new circle;
c1->radius = 9;
bool output1 = c1->cmp(c1);
string str1 = output1 ? "c1 is bigger than 10" : "c1 is not bigger than 10";
cout << str1 << endl;
circle c2;
c2.radius = 100;
bool output2 = c2.cmp(&c2);
string str2 = output2 ? "c2 is bigger than 10" : "c2 is not bigger than 10";
cout << str2 << endl;
return 0;
}
物件的參考
參考和指標最大的差異是參考必須初始化,而指標不用。 簡單的做一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using namespace std;
class circle{
private:
double girth;
double area;
double volume;
public:
int radius;
int height;
void change(circle & c){
c.radius = 20;
}
};
int main(){
circle cir;
cir.radius = 10;
cir.change(cir);
cout << cir.radius << endl;//output = 20
return 0;
}
物件導向封裝
到目前為止感覺class和struct感覺沒有太大的差別,此時就來說說封裝吧,前面有稍微的鋪梗,前面大致上介紹了private和public,這邊我就直接用。
舉個例子,平常我們在使用class裡的值時不會有太大的問題,但是如果你今天是開發者,要給使用者使用你開發的class的話,可能有些地方不希望使用者去更改到,而使用大多不知情,此時怎麼辦呢?這時就要用到封裝了,我拿circle為例,今天如果我們要求周長,而周長是半徑乘二乘3.14,我們必須按照這個規矩來計算,所以今天為了防範使用者不是利用上述算式來求得的周長,所以此時我們樣將周長封裝,此時使用者就不會犯這個錯了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using namespace std;
class circle{
private:
double girth;
double area;
double volume;
public:
int radius;
int height;
double get_girth(){
return radius*2*3.14;
}
double get_area(){
return radius*radius*3.14;
}
double get_volume(){
return get_area()*height;
}
};
int main(){
circle *c1 = new circle;
c1->radius = 10;
c1->height = 20;
cout << c1->get_area() << endl;
cout << c1->get_girth() << endl;
cout << c1->get_volume() << endl;
return 0;
}1
2
3
4
5
6
7
8
9
10
11
using namespace std;
int main(){
bmi student;
student.get_height(171.2);
student.get_weight(73.3);
cout << student.get_bmi() << endl;//ouptut = 25.009
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class bmi{
private:
double height = 100;
double weight = 100;
double BMI;
public:
void get_height(double h);
void get_weight(double w);
double get_bmi();
};
void bmi::get_height(double h){
if(h > 1 && h < 300) height = h;
}
void bmi::get_weight(double w){
if(w > 1 && w < 500) weight = w;
}
double bmi::get_bmi(){
height /= 100;
BMI = weight/(height*height);
return BMI;
}