目录
前言
C++面向对象的三大特性是:封装,继承,多态(本文讲的是封装)
在C++的眼里,万事万物均为对象,对象都有属性和行为
例如:
人可以作为一个对象
属性有:姓名、年龄、身高、体重……;
行为有:跑,跳,吃饭,睡觉,唱歌,生气,开心,哭泣等……
花也可以作为一个对象
属性有:颜色,高度,种类……
行为有:发芽,生长,开花,释放花香,枯萎…….
人有各自所处的环境,包括职业,所在区域,我们都被封装在这一个存在变化的特定区域内,和一个集体一起表现出这个集体的特性,且其他集体对我们这个集体有访问权限限制
花也被封装在一个特定的环境里,或温室,或野外
这就是封装
具有相同性质的对象,我们把它归之为类,比如人属于人类,花属于花类
而人又归属于灵长类动物,所以继承自父类(灵长类)
而花又属于父类(植物类)的继承
人可以分为很多种,根据属性和行为可以分出年轻的正在跑的人,矮的正在睡觉的人……
花也可以分为很多种,红色的释放玫瑰香的花,白色的释放栀子香的花……
这就是多态
一、属性的行为作为整体
1.封装的意义:
-
将属性作为一个整体,表现生活中的事物
-
将属性和行为加以权限控制
1.1封装的意义一——基本语法
在设计类时,属性和行为写在一起,表现事物
语法 class{访问权限: 属性/行为};
实例:
把圆类的属性和行为作为一个整体来体现Circle这个类
设计一个圆类,求圆的周长,代码有注释,跟着敲一遍就懂了
类和对象的关系就是,类是建筑物的蓝图,而对象是具体建造出来的建筑物,类不是一个具体的内容,我们得创建一个类的对象来获取具体的内容(获得一些实质性的东西)
类中的属性通常是一些变量比如这个例子中的double r;
类中的行为通常是一些函数比如这个例子中的:
double cirLen(r)
{
return 2 * pi*r;
}
#include
using namespace std;
#define pi 3.14//宏定义pi的值是3.14
//const double pi 3.14//也可以在main外的全局区域定义一个常量pi
class Circle//定义了一个圆类
{
public://访问权限是公开的
//属性,半径
double r;
double cirLen(r)//传入半径方便计算周长
{
return 2 * pi*r;//返回值是周长
}
};
int main()
{
//实例化Circle类
//在调用时先创建一个类变量,通过圆类创建一个具体的对象
Circle c;
//再用创建好的对象来访问类里面的行为(函数)或属性(double r;)
double r = 7.777;
int result= c.cirLen(r);
cout << "圆的周长是:" << result << endl;//输出圆的周长
//当然我们也可以让用户输入半径,然后执行自动调用计算出周长
cout << "请输入圆的半径:" << endl;
cin >> r;//录入用户输入的数据
cout << "用户输入的半径计算出来的圆的周长是:"<
输出结果是:
1.2案例(设计一个学生类)
设计一个学生类,学生的属性有姓名、学号,可以给学号和姓名赋值,也可以显示学号和姓名
如果报错说:没有与XXX相匹配的运算符,那么多半是没有包含头文件,比如我们在用到string的时候要包含一个也叫string的头文件,这样才不会报错
#include
#include
using namespace std;
class Student
{
public:
//学生类的属性
string stuNum;//学号,用字符串类型,要加上头文件#include
string stuName;//学生姓名
//学生类的行为
void SetInfor()//设置学生信息,给学生的属性赋值的函数
{
cout << "请输入学生姓名:" << endl;
cin >> stuName;
cout << "请输入学生学号:" << endl;
cin >> stuNum;
}
void showInfor()//显示学生信息(姓名学号)的函数
{
cout << "学生的姓名:" << stuName << endl;
cout << "学生的学号:" << stuNum << endl;
}
};
int main()
{
//创建学生类的对象
Student stu;
//利用对象访问其中的行为
stu.SetInfor();//设置学生的姓名学号
stu.showInfor();//展示用户设置的学生的姓名学号
system("pause");
return 0;
}
我们可以给类里面的属性(变量)赋值后show出来
#include
#include
using namespace std;
class Student
{
public:
//学生类的属性
string stuNum;//学号,用字符串类型,要加上头文件#include
string stuName;//学生姓名
//学生类的行为
void SetInfor()//设置学生信息,给学生的属性赋值的函数
{
cout << "请输入学生姓名:" << endl;
cin >> stuName;
cout << "请输入学生学号:" << endl;
cin >> stuNum;
}
void showInfor()//显示学生信息(姓名学号)的函数
{
cout << "学生的姓名:" << stuName << endl;
cout << "学生的学号:" << stuNum << endl;
}
};
int main()
{
//创建学生类的对象
Student stu;
//利用对象访问其中的行为
//用户输入的情况下的输出showInfor
stu.SetInfor();//设置学生的姓名学号
stu.showInfor();//展示用户设置的学生的姓名学号
//程序员设定(赋值的情况下的showInfor输出)
cout << "---------------**---------------" << endl;
stu.stuNum = "20170911";
stu.stuName = "罗马星星";
stu.showInfor();
system("pause");
return 0;
}
通过类里面的函数也可以给相应属性赋值(比如在函数里面改名字,改学号)
//通过函数更改属性
void setNewInfo(string name, string num)
{
stuName = name;
stuNum = num;
}
//通过函数进行赋值的操作调用
cout << "---------------**---------------" << endl;
cout << "通过类中的函数进行赋值的调用显示" << endl;
stu.setNewInfo("张三", "20808089");
stu.showInfor();
如果我们像把它做成一个学生信息管理系统,让用户可以多次录入学生信息那么只需要参考之前写的博文 通讯录管理系统,依葫芦画瓢就好了(甚至此处会更简单至少不用case那么多个选项,直接用if语句)
1.3封装的意义二——访问权限
三种访问权限(作用域)
publiuc:公有权限,成员 类内可以访问,类外也可以访问
protected:保护权限,成员 类内可以访问,类外不可以访问
private:私有权限,成员 类内可以访问,类外不可以访问
protected和private的区别在继承中会有所体现
父类的protected权限,子类可以访问(这个算是家族秘密,你作为家庭中的一员,可以知道)
而父类的private权限,子类不可以访问(这个相当于私生活)
#include
using namespace std;
#include
class Person
{
public://作用域公有权限,类内,类外都可以访问
//公有权限
string name;//公有权限成员的属性,姓名是共有权限
protected:
//保护权限,类内可以访问,类外不可以访问
int age;//年龄是保护权限
private:
//私有权限,类内可以访问,类外不可以访问
string address;//家庭住址,私有权限
public://公有,类外可以访问
void setInfo(string p_name, int p_age, string p_address)
{
name = p_name;
age = p_age;
address = p_address;
}
void showInfo()
{
cout << "姓名" << name << endl;//name是公有权限,在类内访问,可以允许
cout << "年龄" << age << endl;//age是保护权限,在类内可以访问
cout << "住址:" << address << endl;//address是私有权限,在类内可以访问
}
};
int main()
{
//创建Person类的对象
Person p;
p.name = "张三";//name是Person的公有权限成员可以在类外访问并修改赋值
p.age = 12;//age是保护权限,在类外访问报错
p.address = "北京海淀";//address是私有成员,类外不可以访问
//调用赋值函数setInfo
p.setInfo("李四", 22, "四川");
p.showInfo();//显示信息
system("pause");
return 0;
}
p.name = “张三”;//name是Person的公有权限成员可以在类外访问并修改赋值
p.age = 12;//age是保护权限,在类外访问报错
p.address = “北京海淀”;//address是私有成员,类外不可以访问
只有把在类外错误访问的部分注释掉才能正常运行
在继承中的访问权限差异
继承的语法是 class
class Lisa:public Person
{
};
//把Lisa作为Person的子类(继承)
//可以访问父类Person中的age 保护权限,但是不可以访问父类的私有权限成员address
class Lisa:public Person//子类Lisa公有继承父类(也可以叫基类)Person
{
public:
void showInfo()
{
cout<< "父类Person的公有权限成员:name" << name << endl;//可以访问
cout << "父类Person的保护权限成员:age" << age << endl;//可以访问
cout << "父类Person的私有权限成员:address" << address << endl;//报错,不可以访问
}
};
#include
using namespace std;
#include
class Person
{
public://作用域公有权限,类内,类外都可以访问
//公有权限
string name;//公有权限成员的属性,姓名是共有权限
protected:
//保护权限,类内可以访问,类外不可以访问
int age;//年龄是保护权限
private:
//私有权限,类内可以访问,类外不可以访问
string address;//家庭住址,私有权限
public://公有,类外可以访问
void setInfo(string p_name, int p_age, string p_address)
{
name = p_name;
age = p_age;
address = p_address;
}
void showInfo()
{
cout << "姓名" << name << endl;//name是公有权限,在类内访问,可以允许
cout << "年龄" << age << endl;//age是保护权限,在类内可以访问
cout << "住址:" << address << endl;//address是私有权限,在类内可以访问
}
};
//把Lisa作为Person的子类(继承)
//可以访问父类Person中的age 保护权限,但是不可以访问父类的私有权限成员address
class Lisa:public Person//子类Lisa公有继承父类(也可以叫基类)Person
{
public:
void showInfo()
{
cout<< "父类Person的公有权限成员:name" << name << endl;//可以访问
cout << "父类Person的保护权限成员:age" << age << endl;//可以访问
cout << "父类Person的私有权限成员:address" << address << endl;//报错,不可以访问
}
};
int main()
{
//创建Person类的对象
Person p;
//p.name = "张三";//name是Person的公有权限成员可以在类外访问并修改赋值
//p.age = 12;//age是保护权限,在类外访问报错
//p.address = "北京海淀";//address是私有成员,类外不可以访问
//调用赋值函数setInfo
p.setInfo("李四", 22, "四川");
p.showInfo();//显示信息
system("pause");
return 0;
}
这就是protected和private在继承中的差异
二、class和struct的区别
在C++中struct和class的唯一区别就是默认访问权限不同
-
struct的默认访问权限是共有的
-
class默认访问权限是私有的
#include
#include
using namespace std;
struct student//默认权限是公有在其他地方可以访问
{
string stu_name;
};
class teacher//类的默认全是是私有,类内没有加上public字眼,只有一段语句就属于默认的私有权限
{
string tea_name;
};
int main()
{
//试图访问struct的成员
student stu;//创建结构对象
//用结构对象访问结构体中的成员变量
stu.stu_name = "罗马";//可以在结构体外访问
//试图访问类中的成员
teacher tea;
tea.tea_name="星星";//无法访问,验证了类的默认权限是私有
system("pause");
return 0;
}
三、成员属性私有化
1.好处1:控制属性的读写权限
把类内成员属性(变量划入私有权限区域)在类内公开一个可以连接内外的访问函数,控制私有属性的读写权限(读:获取,写:设置)
创建一个Person类,把成员属性姓名,年龄,地址,全部设为私有private
然后再Person开放一个public权限set函数和get函数进行访问类内的私有属性,再在类外调用这两个函数,间接访问private属性
#include
#include
using namespace std;
class Person
{
public:
//开放权限
void setName(string set_name)//name的写(设置)权限
{
name = set_name;
}
string getName()//name的读权限(获取权限)
{
return name;//返回私有权限的成员name
}
//void setAge(int set_age)//age的写(设置权限),注释掉,不开放
//{
// age = set_age;
//}
int getAge()//age的只读权限,获取age
{
return age;//返回私有权限中的成员属性age
}
//住址的只写权限(设置权限)
void setAddress(string set_address)
{
address = set_address;
}
private:
string name;//姓名 开放读写权限
int age = 20;//给年龄设置一个默认参数 年龄 开放只读权限
string address;//住址 开放只写权限
};
int main()
{
Person p;//创建Person类对象
//在类外用对象访问开放权限的读写函数权限,控制相应私有成员属性的读写
p.setName("王二");//修改姓名为王二
cout << "输出获取到的姓名:" << p.getName() << endl;
cout << "输出获取到的年龄:" << p.getAge() << endl;//此时输出的是默认值20岁
p.setAddress("北京海淀");//address只开放了写权限
//由于setAddress没有返回值,所以呢我们是不能进行输出的
system("pause");
return 0;
}
我们可以对用户输入的年龄一栏加以控制,首先给age开放一个可写(set)的权限,再控制用户可以写的年龄范围(0~150岁),超出范围则提示用户输入超出范围,并且返回一个默认值0,说明用户年龄设置不成功
#include
#include
using namespace std;
class Person
{
public:
//开放权限
void setName(string set_name)//name的写(设置)权限
{
name = set_name;
}
string getName()//name的读权限(获取权限)
{
return name;//返回私有权限的成员name
}
void setAge(int set_age)//开放age的写权限,并且控制用户的输入
{
//用if语句控制用户设置的年龄范围在0~150岁之间
if (set_age < 0 || set_age>150)
{
//若发生超限情况,把private中的age强制改为0,并输出
age = 0;//设置一个默认返回值,确保程序安全运行
cout << "您输入的年龄超出正常人类的范围啦!" << endl;
return;//返回0,错误值
}
//用户输入正常数据则返回用户输入的数据
age = set_age;
}
int getAge()//age的只读权限,获取age
{
return age;//返回私有权限中的成员属性age
}
//住址的只写权限(设置权限)
void setAddress(string set_address)
{
address = set_address;
}
private:
string name;//姓名 开放读写权限
int age ;//给年龄设置一个默认参数 年龄 开放只读权限
string address;//住址 开放只写权限
};
int main()
{
Person p;//创建Person类对象
//在类外用对象访问开放权限的读写函数权限,控制相应私有成员属性的读写
//p.setName("王二");//修改姓名为王二
//cout << "输出获取到的姓名:" << p.getName() << endl;
p.setAge(11000);//超出范围会输出报错结果
cout << "p.setAge(11000)的输出:" << (int)p.getAge() << endl;
p.setAge(19);//正常输出
cout << "p.setAge(19)的输出" << p.getAge() << endl;
//cout << "输出获取到的年龄:" << p.getAge() << endl;
//p.setAddress("北京海淀");//address只开放了写权限
//由于setAddress没有返回值,所以呢我们是不能进行输出的
system("pause");
return 0;
}
p.setAge(11000);//超出范围会报错
cout << “p.setAge(11000)的输出:” << p.getAge() << endl;
p.setAge(19);//正常输出
cout << “p.setAge(19)的输出” << p.getAge() << endl;
四、案例
1.立方体类
设计立方体类,求出立方体的面积和体积,分别用全局函数和成员函数判断两个立方体是否相等
#include
#include
using namespace std;
class Cube//立方体的英文是the cube
{
public://共有权限
double L;//立方体的长 成员属性
double W;//立方体的宽 成员属性
double H;//立方体的高 成员属性
//public://开放权限
// //double set_L;//外界供用户输入的长
// //double set_W;//外界供用户输入的宽
// //double set_H;//外界供用户输入的高
void setLWH(double set_L, double set_W, double set_H)//设置长宽高的函数,便于外部对私有属性的写(设置set)
{
cout << "请输入立方体的长:" << endl;
cin >> set_L;
L = set_L;
cout << "请输入立方体的宽:" << endl;
cin >> set_W;
W = set_W;
cout << "请输入立方体的高:" << endl;
cin >> set_H;
H = set_H;
}
double calArea()//立方体表面积计算函数
{
//长方体的表面积=(长×宽+宽×高+长×高)×2
//判断,如果是正方体,长宽高相等
//正方体表面积计算公式=棱长×棱长×6,长*宽*6
if (L == W == H)
{
return L * W * 6;//如果是正方体
}
else//否则可判定为长方体,执行长方体面积计算结果
{
double area = (L*W + W * H + L * H) * 2;
return area;
}
}
double calV()//立方体的体积计算函数(成员函数)
{
if (L == W == H)//正方体的体积计算公式V=a×a×a,L*W*H
{
return L * L*L;
}
else//长方体体积计算公式长×宽×高
{
return L * W*H;
}
}
//成员函数判断两个立方体是否相等
//class Cube类内,只需要传入一个外部类对象再跟类内部的做对比就可以判断了
void isEqualityClass(Cube & cu3)
{
if (L == cu3.L&&W == cu3.W&&H == cu3.H)
{
cout << "成员函数判断出两个立方体相等" << endl;
}
else
{
cout << "成员函数判断出两个立方体相等" << endl;
}
}
};
//全局函数判断两个立方体是否相等
void isEquality(Cube & cu, Cube &cu2)//传入两个对象的引用
{
if (cu.L == cu2.L&&cu.W == cu2.W&&cu.H == cu2.H)//如果两个对象的LWH都相等
{
cout << "全局函数判断出两个立方体相等" << endl;
}
else
{
cout << "全局函数判断出两个立方体不相等" << endl;
}
}
int main()
{
Cube cu;
//一键输入立方体的长宽高
cu.setLWH(10, 20, 30);//参数可以随便输入,因为我们在成员函数体内设置了由用户输入,会由用户输入的数据替代原始数据输出
cout << "面积" << cu.calArea() << endl;
cout << "体积" << cu.calV() << endl;
Cube cu2;
cu2.setLWH(1, 2, 3);
cout << "cu2的面积" << cu2.calArea() << endl;
cout << "cu2的体积" << cu2.calV() << endl;
isEquality(cu, cu2);
cu.isEqualityClass(cu2);
system("pause");
return 0;
}
输出结果,可以设置,计算也可以用全局函数和成员函数判断
2.点和圆的关系
设计一个圆类(Circle)和一个点类(Point),计算圆和点之间的关系
圆和点有什么关系?
点在圆内,点在圆边上,点在圆外
假设圆的半径为r,点到圆心的距离为d,则有:d<r点在圆内,d=r点在圆上,d>r点在圆外
点与圆的位置关系 点P(x1,y1) 与圆(x-a)²+(y-b)²=r²的位置关系:
(1)当(x1-a)²+(y1-b)²>r²时,则点P在圆外。
(2)当(x1-a)²+(y1-b)²=r²时,则点P在圆上。
(3)当(x1-a)²+(y1-b)²<r²时,则点P在圆内。
圆的标准方程(x-a)²+(y-b)²=r²中,有三个参数a、b、r,即圆心坐标为(a,b),只要求出 a、b、r,这时圆的方程就被确定,因此确定圆方程,须三个独立条件,其中圆心坐标是圆 的定位条件,半径是圆的定形条件。
#include
#include
using namespace std;
class Circle//圆类
{
public:
double cX;//圆心的x坐标
double cY;//圆心的Y坐标
double r;//圆半径
public:
void setR(double set_r,double set_cX,double set_cY)
{
cout << "请输入圆的半径" << endl;
cin >> set_r;
r = set_r;
cout << "请输入圆心的x坐标" << endl;
cin >> set_cX;
cX = set_cX;
cout << "请输入圆心的y坐标" << endl;
cin >> set_cY;
cY = set_cY;
}
};
class Point//点类
{
public:
double pX;//点的x坐标
double pY;//点的y坐标
public:
void setXY(double set_x, double set_y)//设置点的xy坐标
{
cout << "请输入点的x坐标" << endl;
cin >> set_x;
pX = set_x;
cout << "请输入点的y坐标" << endl;
cin >> set_y;
pY = set_y;
}
};
//用全局函数判断点和圆的关系
void isLocation(Circle c,Point p)
{
double d = ((p.pX - c.cX)*(p.pX - c.cX) + (p.pY - c.cY)*(p.pY - c.cY));
double sqrtR = c.r*c.r;
if (d > sqrtR)//距离大于半径
{
cout << "点在圆外" << endl;
}
if (d == sqrtR)//距离等于半径
{
cout << "点在圆上" << endl;
}
if (d < sqrtR)//距离小于半径的平方
{
cout << "点在圆内" << endl;
}
}
int main()
{
Circle c;//创建圆的对象
c.setR(1, 2, 3);//这里的参数可以随便传,结果以用户输入的为准
Point p;//创建点的对象
p.setXY(1, 2);//这里的参数可以随便传,结果以用户输入的为准
//调用全局函数判断点和圆的关系
isLocation(c, p);
system("pause");
return 0;
}
程序的运行结果如下
费曼学习法,边学习,边cout
Original: https://blog.csdn.net/qq_58619891/article/details/127819679
Author: 洛里斯不学习
Title: C++类与对象——封装
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/660807/
转载文章受原作者版权保护。转载请注明原作者出处!