11 封装
C++ 面向对象的三大特性为:封装、继承、多态。本章先讲封装。
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
11.1 封装的意义
11.1.1 属性和行为作为一个整体
在设计类的时候,属性和行为写在一起,表现事物。
语法:
1
| class 类名 { 访问权限: 属性 / 行为 };
|
示例 1:设计一个圆类,求圆的周长
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 31 32 33 34 35 36 37
| #include <iostream> using namespace std;
const double PI = 3.14;
class Circle { public:
int m_r;
double calculateZC() { return 2 * PI * m_r; } };
int main() {
Circle c1; c1.m_r = 10;
cout << "圆的周长为: " << c1.calculateZC() << endl;
system("pause");
return 0; }
|
示例 2:设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
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 31 32 33 34 35 36 37
| #include <iostream> using namespace std; #include <string>
class Student { public:
string m_Name; int m_Id;
void showStudent() { cout << "姓名: " << m_Name << " 学号: " << m_Id << endl; }
void setName(string name) { m_Name = name; } };
int main() {
Student s1; s1.setName("张三"); s1.m_Id = 1; s1.showStudent();
system("pause");
return 0; }
|
总结:类中的属性和行为,我们统一称为成员。成员属性为成员变量,成员函数为成员行为。
11.1.2 访问权限
类在设计时,可以把属性和行为放在不同的权限下,加以控制。
访问权限有三种:
- public 公共权限:成员 类内可以访问,类外可以访问
- protected 保护权限:成员 类内可以访问,类外不可以访问,子类可以访问
- private 私有权限:成员 类内可以访问,类外不可以访问,子类不可以访问
示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <iostream> using namespace std; #include <string>
class Person { public:
string m_Name;
protected:
string m_Car;
private:
int m_Password;
public:
void func() { m_Name = "张三"; m_Car = "拖拉机"; m_Password = 123456; } };
int main() {
Person p;
p.m_Name = "李四";
system("pause");
return 0; }
|
11.2 struct 和 class 的区别
在 C++ 中 struct 和 class 的区别在于:默认的访问权限不同。
- struct 默认权限为公共
- class 默认权限为私有
示例:
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
| #include <iostream> using namespace std;
class C1 { int m_A; };
struct C2 { int m_B; };
int main() {
C2 c2; c2.m_B = 100;
system("pause");
return 0; }
|
11.3 成员属性设置为私有
优点 1:将所有成员属性设置为私有,可以自己控制读写权限。
优点 2:对于写权限,我们可以检测数据的有效性。
示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <iostream> using namespace std; #include <string>
class Person { public:
void setName(string name) { m_Name = name; }
string getName() { return m_Name; }
int getAge() { return m_Age; }
void setAge(int age) { if (age < 0 || age > 150) { cout << "你这个老妖精!" << endl; return; } m_Age = age; }
void setLover(string lover) { m_Lover = lover; }
private:
string m_Name;
int m_Age;
string m_Lover; };
int main() {
Person p; p.setName("张三"); cout << "姓名: " << p.getName() << endl;
p.setAge(50); cout << "年龄: " << p.getAge() << endl;
p.setLover("苍井");
system("pause");
return 0; }
|
11.4 封装案例一:立方体类
案例描述:设计立方体类(Cube),求出立方体的面积和体积,分别用全局函数和成员函数判断两个立方体是否相等。
示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| #include <iostream> using namespace std;
class Cube { public:
void setL(int l) { m_L = l; }
int getL() { return m_L; }
void setW(int w) { m_W = w; }
int getW() { return m_W; }
void setH(int h) { m_H = h; }
int getH() { return m_H; }
int calculateS() { return 2 * m_L * m_W + 2 * m_W * m_H + 2 * m_L * m_H; }
int calculateV() { return m_L * m_W * m_H; }
bool isSameByClass(Cube& c) { if (m_L == c.getL() && m_W == c.getW() && m_H == c.getH()) { return true; } return false; }
private:
int m_L; int m_W; int m_H; };
bool isSame(Cube& c1, Cube& c2) { if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH()) { return true; } return false; }
int main() {
Cube c1; c1.setL(10); c1.setW(10); c1.setH(10);
cout << "c1的面积为: " << c1.calculateS() << endl; cout << "c1的体积为: " << c1.calculateV() << endl;
Cube c2; c2.setL(10); c2.setW(10); c2.setH(11);
bool ret = isSame(c1, c2); if (ret) { cout << "全局函数判断:c1和c2是相等的" << endl; } else { cout << "全局函数判断:c1和c2是不相等的" << endl; }
ret = c1.isSameByClass(c2); if (ret) { cout << "成员函数判断:c1和c2是相等的" << endl; } else { cout << "成员函数判断:c1和c2是不相等的" << endl; }
system("pause");
return 0; }
|
11.5 封装案例二:点和圆关系
案例描述:设计一个圆形类(Circle)和一个点类(Point),计算点和圆的关系。
已知一个圆和一个点,判断点与圆的位置关系:圆内、圆外、圆上。
圆的参数:圆心坐标(x,y)和半径;点参数:坐标(x,y)。
示例:
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| #include <iostream> using namespace std;
class Point { public:
void setX(int x) { m_X = x; }
int getX() { return m_X; }
void setY(int y) { m_Y = y; }
int getY() { return m_Y; }
private:
int m_X; int m_Y; };
class Circle { public:
void setR(int r) { m_R = r; }
int getR() { return m_R; }
void setCenter(Point center) { m_Center = center; }
Point getCenter() { return m_Center; }
private:
int m_R; Point m_Center; };
void isInCircle(Circle& c, Point& p) { int distance = (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) + (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
int rDistance = c.getR() * c.getR();
if (distance == rDistance) { cout << "点在圆上" << endl; } else if (distance > rDistance) { cout << "点在圆外" << endl; } else { cout << "点在圆内" << endl; } }
int main() {
Circle c; c.setR(10); Point center; center.setX(10); center.setY(0); c.setCenter(center);
Point p; p.setX(10); p.setY(10);
isInCircle(c, p);
system("pause");
return 0; }
|
总结:封装就是属性和行为写在一起,并用访问权限控制对外的读写;保持成员属性私有,对外只暴露安全的成员函数,是良好类设计的基础。