4 类和对象
C++面向对象的三大特性为:封装、继承、多态
C++以万事万物都皆为对象,对象上有其属性和行为
例如:
人可以作为对象,其属性有姓名、年龄、身高、体重…,行为有走、跑、跳、吃饭、唱歌…
车也可以作为对象,其属性有轮胎、方向盘、车灯…,行为有载人、放音乐、放空调…
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
4.1 封装
4.1.1 封装的意义
封装是C++面向对象三大特性之一
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装意义一: 在设计类的时候,属性和行为写在一起,表现事物
语法格式:
class 类名{
访问权限:
属性;
访问权限:
行为;
};
示例1: 设计一个圆类,求圆的周长
示例代码:
#include<iostream>
using namespace std;
//定义一个常量PI来代表圆周率
const double PI = 3.14;
//封装一个圆类,class代表设计一个类,类名为Circle
class Circle{
public: //访问权限:代表公共的权限,即所有其他类都可以创建园类实例化对象之后,获取园类的属性和调用园类的方法
//属性列表
//半径
int m_r;
//行为列表
//获取到圆的周长
double calculateZC(){
//获取圆的周长公式:2 * pi * r,并返回计算结果!
return 2 * PI * m_r;
}
};
int main() {
//通过圆类,创建圆的实例化对象c1,就是一个真实的园,简而言之,园类是一个模具,c1是模具制作出来的实物
Circle c1;
//注意:给圆对象c1属性半径进行赋值通过对象.属性方式操作
c1.m_r = 10;
//注意:给圆对象c1方法调用通过对象.方法方式操作获取计算结果
cout << "圆的周长为: " << c1.calculateZC() << endl;
system("pause");
return 0;
}
示例2: 设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
代码示例:
#include<iostream>
using namespace std;
class Student {
//属性:类中属性即为成员属性,也可以称为成员变量
public://访问权限:代表公共的权限
//姓名
string m_Name;
//学号
int m_Id;
//方法列表:类中方法即为成员方法,也可以称为成员函数
public:
//定义一个showStudent方法来展示学生姓名和学号
void showStudent() {
cout << "学生姓名:" << m_Name << " 学号:" << m_Id << endl;
}
//定义一个无返回值方法setName来给Student类中m_Name属性进行赋值
void setName(string name) {
m_Name = name;
}
//定义一个有返回值类型方法getName来获取Student类中m_Name属性中的值,注意:返回值类型需要和返回的属性值的类型对应
string getName() {
return m_Name;
}
//定义一个无返回值方法setId来给Student类中m_Id属性进行赋值
void setId(int id) {
m_Id = id;
}
//定义一个有返回值类型方法getId来获取Student类中m_Id属性中的值
int getId() {
return m_Id;
}
};
int main() {
//通过Student类,创建实例化对象stu
Student stu;
//注意:给对象stu属性进行赋值通过对象.属性方式操作
stu.m_Name = "qzp";
stu.m_Id = 1001;
//注意:给圆对象stu1方法调用通过对象.方法方式操作来展示学生姓名和学号
stu.showStudent();
//注意:通过Student类中方法给实例化对象stu属性进行赋值通过对象.setxxx(value)方式操作
stu.setName("QZP");
stu.setId(1111);
//注意:通过Student类中方法给实例化对象stu属性进行获取值通过对象.getxxx()方式操作
cout << "学生姓名:" << stu.getName() << " 学号:" << stu.getId() << endl;
system("pause");
return 0;
}
总结:
- 使用对象属性:对象名.成员变量
- 使用对象方法:对象名.方法名
- 同一个类的每一个对象有不同的成员变量的存储空间
- 同一个类中成员方法中可以定义set方法来来使用对象属性进行赋值以及get方法来获取对象属性的值
- 同一个类的每个对象共享该类的方法
封装意义二: 类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限 | 权限含义 | 权限范围 |
---|---|---|
public | 公共权限 | 类内可以访问 类外可以访问 |
protected | 保护权限 | 类内可以访问 类外不可以访问 |
private | 私有权限 | 类内可以访问 类外不可以访问 |
代码示例:
#include<iostream>
using namespace std;
//定义一个Person类
class Person {
//成员变量
public://公共权限
//姓名,简单理解:在公共场合,所有人都可以称呼你的姓名
string m_Name;
protected://保护权限
//汽车之主,简单理解:在手续完成后,你对该车就有了保护权限,任何其他人使用都需要经过你的允许
string m_Car_Owner;
private://私有权限
//银行卡密码,简单理解:你的经济收入都在这个卡里,任何其他人都无权使用
int m_Bank_Card_Password;
//成员方法
public:
void setPersonFormation() {
//所有权限的成员变量均可以在本类中访问
m_Name = "qzp";
m_Car_Owner = "qzp";
m_Bank_Card_Password = 123456;
cout << "姓名: " << m_Name << " 车主:" << m_Car_Owner << " 银行卡密码:" << m_Bank_Card_Password << endl;
}
};
int main() {
//创建一个Person实例化对象p
Person p;
//使用对象属性:对象名.成员变量
p.m_Name = "qzy";//公共权限可以访问
//p.m_Car_Owner = "qzy";//保护权限类外访问不到
//p.m_Bank_Card_Password = 999999;//私有权限类外访问不到
//使用对象方法:对象名.方法名
p.setPersonFormation();
system("pause");
return 0;
}
4.1.2 struct和class区别
在C++中 struct和class唯一的区别就在于 默认的访问权限不同
区别:
struct
默认为公共权限class
默认为私有权限
#include<iostream>
using namespace std;
//定义一个C1类
//注意:当类中的成员变量和成员方法没有用关键字权限来控制,默认为私有权限,类外不可访问
class C1 {
int m_A; //默认是私有权限
void function() {
m_A = 1000;
cout << m_A <<endl;
}
};
//定义一个C2结构体
//注意:当结构体中的成员变量和成员方法没有用关键字权限来控制,默认为公共权限,均可访问
struct C2 {
int m_A; //默认是公共权限
void function() {
m_A = 1000;
cout << m_A << endl;
}
};
int main() {
//创建一个C1类实例化对象c1
C1 c1;
//c1.m_A = 10; //错误,不可访问,访问权限默认是私有权限
//c1.function();//错误,不可访问,访问权限默认是私有权限
//结构体变量创建,注意:struct 关键字可以省略
struct C2 c2;
c2.m_A = 10; //正确,访问权限默认是公共权限
c2.function();//正确,访问权限默认是公共权限
system("pause");
return 0;
}
4.1.3 成员属性设置为私有
优点1: 将所有成员属性设置为私有,可以自己控制读写权限
优点2: 对于写权限,我们可以检测数据的有效性
代码示例:
#include<iostream>
using namespace std;
class People {
//成员变量均为私有权限,类外无法访问,在公共权限下通过set方法和get成员方法来控制对私有属性的访问
private:
//姓名(可读可写)
string m_Name;
//年龄(可读可写)
int m_Age = 0;
//爱人(只写)
string m_Lover;
//成员方法均为公共权限
public:
//定义setName/getName方法对m_Name可读可写
void setName(string name) {
m_Name = name;
}
string getName(){
return m_Name;
}
//定义setAge/getAge方法对m_Age可读可写
void setAge(int age) {
//对于输入的年龄进行校验来判断数据是否有效
if (age < 0 || age > 150) {
cout << "你已成仙!" << endl;
return;
}
m_Age = age;
}
int getAge() {
return m_Age;
}
//定义setLover方法对m_Lover可写
void setLover(string lover) {
m_Lover = lover;
}
};
int main() {
//创建一个实例化对象
People p;
//姓名设置
p.setName("qzp");
cout << "姓名: " << p.getName() << endl;
//年龄设置
p.setAge(25);
cout << "年龄: " << p.getAge() << endl;
//爱人设置
p.setLover("FL");
//cout << "爱人: " << p.getLover() << endl; //报错,无getLover方法,只写属性,不可以读取
system("pause");
return 0;
}
练习案例1:设计立方体类
设计立方体类(Cube)
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等。
代码示例:
#include<iostream>
using namespace std;
//立方体类设计
//1.创建一个立方体类
//2.设计属性:长、宽、高
//3.设计行为:获取立方体的面积和体积
//4.分别利用全局函数和成员函数,判断两个立方体是否相等
class Cube {
//成员变量
private:
//长
int m_Length;
//宽
int m_Width;
//高
int m_Height;
//成员方法
public:
//设置长度
void setLength(int length) {
m_Length = length;
}
//获取长度
int getLength() {
return m_Length;
}
//设置宽度
void setWidth(int width) {
m_Width = width;
}
//获取宽度
int getWidth() {
return m_Width;
}
//设置高度
void setHeight(int height) {
m_Height = height;
}
//获取高度
int getHeight() {
return m_Height;
}
//获取立方体的表面积
int surface_Area() {
return 2 * m_Length + 2 * m_Width + 2 * m_Height;
}
//获取立方体的体积
int volume() {
return m_Length * m_Width * m_Height;
}
//利用成员函数判断两个立方体是否相等
bool isSameByClass(Cube &otherCube) {
if (m_Length == otherCube.m_Length && m_Width == otherCube.m_Width && m_Height == otherCube.m_Height) {
return 1;
}
return 0;
}
};
//利用全局函数判断两个立方体是否相等
bool isSame(Cube &c1,Cube &c2) {
return (c1.getLength() == c2.getLength() ? 1 : 0) && (c1.getWidth() == c2.getWidth() ? 1 : 0) && (c1.getHeight() == c2.getHeight() ? 1 : 0);
}
int main() {
//创建第一个立方体
//Cube类实例化对象c1
Cube c1;
//因对象的属性是私有权限,通过公共权限的成员方法set给对象的属性赋值
c1.setLength(10);
c1.setWidth(10);
c1.setHeight(10);
//获取c1的表面积和体积
cout << "c1的表面积为:" << c1.surface_Area() << endl;
cout << "c1的体积为:" << c1.volume() << endl;
//创建第二个立方体
//Cube类实例化对象c2
Cube c2;
//因对象的属性是私有权限,通过公共权限的成员方法set给对象的属性赋值
c2.setLength(10);
c2.setWidth(11);
c2.setHeight(10);
//获取c1的表面积和体积
cout << "c1的表面积为:" << c2.surface_Area() << endl;
cout << "c1的体积为:" << c2.volume() << endl;
bool flag1 = isSame(c1,c2);
string result1 = flag1 ? "相等" : "不相等";
cout << "全局函数判断c1和c2" << result1 << endl;
bool flag2 = c1.isSameByClass(c2);
string result2 = flag2 ? "相等" : "不相等";
cout << "成员函数判断c1和c2" << result2 << endl;
system("pause");
return 0;
}
练习案例2:点和圆的关系
设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系。
代码示例:
#include<iostream>
using namespace std;
//设置一个点类
class Point {
//成员变量
private:
//x坐标
int m_x;
//y坐标
int m_y;
public:
//设置x坐标
void setX(int x) {
m_x = x;
}
//获取x坐标
int getX() {
return m_x;
}
//设置y坐标
void setY(int y) {
m_y = y;
}
//获取y坐标
int getY() {
return m_y;
}
};
//设计园类
class Circular {
private:
//半径
int m_r;
//圆心
//注意:在类中可以引用另一个类作为本类中的成员
Point m_Center;
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;
}
};
//判断点和圆的关系
void showPointAndCircleRelation(Circular &c,Point &p) {
//计算圆心和点之间的距离
double distance = pow(pow(abs(c.getCenter().getX() - p.getX()), 2) + pow(abs(c.getCenter().getY() - p.getY()), 2),0.5);
//计算圆的半径
double radius = c.getR();
if (distance > radius) {
cout << "点在圆外" << endl;
}
else if (distance == radius) {
cout << "点在圆上" << endl;
}
else {
cout << "点在圆内" << endl;
}
}
int main() {
//创建一个圆
Circular c;
//设置圆的半径
c.setR(5);
//创建圆心
Point center;
center.setX(5);
center.setY(0);
c.setCenter(center);
//创建一个点
Point spot;
spot.setX(1);
spot.setY(3);
//调用showPointAndCircleRelation函数判断圆和点之间的关系
showPointAndCircleRelation(c,spot);
system("pause");
return 0;
}
针对于上述代码,一个程序中定义了多个类的情况,代码太长,可读性太差,代码不灵活,如何解决呢?
步骤如下:
- 在头文件中定义一个point.h文件
#pragma once
//为了防止头文件重复包含
#include<iostream>
using namespace std;
//设置一个点类
class Point {
//成员变量
private:
//x坐标
int m_x;
//y坐标
int m_y;
//所有类中成员函数皆为声明,不做具体实现
public:
//设置x坐标
void setX(int x);
//获取x坐标
int getX();
//设置y坐标
void setY(int y);
//获取y坐标
int getY();
};
- 在源文件中定义一个point.cpp文件
//引入头文件
#include "point.h";
//注意:
// 1.源文件point.cpp只负责Point类中成员函数的实现
// 2.需要使用类名::指明所有函数是Point类中成员函数的实现
//设置x坐标
void Point::setX(int x) {
m_x = x;
}
//获取x坐标
int Point::getX() {
return m_x;
}
//设置y坐标
void Point::setY(int y) {
m_y = y;
}
//获取y坐标
int Point::getY() {
return m_y;
}
3.同理,对于Circular类,我们也需要这种操作,在头文件中定义一个circular.h文件
#pragma once
#include<iostream>
using namespace std;
#include "point.h"
//设计园类
class Circular {
private:
//半径
int m_r;
//圆心
//注意:在类中可以引用另一个类作为本类中的成员
Point m_Center;
public:
//设置半径
void setR(int r);
//获取半径
int getR();
//设置圆心
void setCenter(Point center);
//获取圆心
Point getCenter();
};
- 在源文件中定义一个circular.cpp文件
#include "circular.h"
//设置半径
void Circular::setR(int r) {
m_r = r;
}
//获取半径
int Circular::getR() {
return m_r;
}
//设置圆心
void Circular::setCenter(Point center) {
m_Center = center;
}
//获取圆心
Point Circular::getCenter() {
return m_Center;
}
- 测试
#include<iostream>
using namespace std;
#include "point.h"
#include "circular.h"
//判断点和圆的关系
void showPointAndCircleRelation(Circular &c,Point &p) {
//计算圆心和点之间的距离
double distance = pow(pow(abs(c.getCenter().getX() - p.getX()), 2) + pow(abs(c.getCenter().getY() - p.getY()), 2),0.5);
//计算圆的半径
double radius = c.getR();
if (distance > radius) {
cout << "点在圆外" << endl;
}
else if (distance == radius) {
cout << "点在圆上" << endl;
}
else {
cout << "点在圆内" << endl;
}
}
int main() {
//创建一个圆
Circular c;
//设置圆的半径
c.setR(5);
//创建圆心
Point center;
center.setX(5);
center.setY(0);
c.setCenter(center);
//创建一个点
Point spot;
spot.setX(1);
spot.setY(3);
//调用showPointAndCircleRelation函数判断圆和点之间的关系
showPointAndCircleRelation(c,spot);
system("pause");
return 0;
}
读万卷书,行万里路,博主会持续更新学习笔记,如有问题,可以留言和私信,我们一起进步!!!