【C++】C++核心编程(四)---类与对象(封装)
1.属性和行为作为整体
C++面向对象的三大特性:封装、继承、多态
C++认为万事万物都皆为对象,对象上有其属性
和行为
人可以作为对象,属性有姓名、年龄、身高、体重…行为有走、跑、跳、吃饭、睡觉…
车也可以作为对象,属性有车牌、车灯、轮胎…行为有载人、放音乐…
具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类
…
封装是C++面向对象三大特性之一
封装的意义
:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
语法
:class 类名{访问权限:属性/行为};
封装意义一: 在设计类时,属性和行为写在一起,表现事物
案例:设计一个圆类,求圆的周长和面积
- 代码实现:
#include <iostream>
using namespace std;
// #define PI 3.14 (宏常量)
const double PI = 3.14;
class Circle
{
// 访问权限:公共权限
public:// 属性 半径int c_R;// 行为1 返回圆的周长double circleL(){return 2 * PI * c_R;}// 行为2 返回圆的面积double circleS(){return PI * c_R * c_R;//return PI * (c_R ^ 2); //写成这样为啥返回25.12???}
};int main() {// 创建一个圆类对象c1// 实例化(通过一个类,创建一个对象的过程)Circle c1;c1.c_R = 10; //给对象c1半径属性赋值cout << "圆对象c1的周长为: " << c1.circleL() << endl;cout << "圆对象c1的面积为: " << c1.circleS() << endl;system("pause");return 0;
}
- 输出结果:
圆对象c1的周长为: 62.8
圆对象c1的面积为: 314
请按任意键继续. . .
注意
:在C++中^
符号表示按位异或运算符。参与运算的两个值,如果两个相应位相同,则结果为0,否则为1。如:10^2=8(10转化为二进制为0000 1010,2转化为二进制为0000 0010,运算后得到的结果为:0000 1000)。在这里也就可以解释为什么PI * (c_R ^ 2) = 25.12了。
2.案例-设计学生类
案例:设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
- 代码实现:
#include <iostream>
using namespace std;
#include <string>// 创建一个学生类
class Student
{
// 权限设置
public:// 属性 姓名和学号string s_Name;int s_Id;// 行为1 姓名赋值void setName(string name){s_Name = name;}// 行为2 姓名获取string getName(){return s_Name;}// 行为3 学号赋值void setId(int id){s_Id = id;}// 行为4 学号获取int getId(){return s_Id;}
};void test()
{// 创建一个学生对象s1Student s1;// 给对象的属性赋值(利用赋值函数)s1.setName("张三李四");s1.setId(20221120);// 获取对象的属性信息(利用获取函数)cout << "学生s1的姓名为:" << s1.getName() << endl;cout << "学生s1的学号为:" << s1.getId() << endl;
}int main() {test();system("pause");return 0;
}
- 输出结果:
学生s1的姓名为:张三李四
学生s1的学号为:20221120
请按任意键继续. . .
知识点补充:
类中的属性和行为 我们统一称为 成员
属性
:又称为成员属性
或者成员变量
行为
:又称为成员函数
或者成员方法
3.访问权限
封装意义二: 类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限
有三种:
public 公共权限
(类内可以访问 类外也可以访问)protected 保护权限
(类内可以访问 类外不可以访问 子类可以访问父类)private 私有权限
(类内可以访问 类外不可以访问 子类不能访问父类)
- 代码演示:
#include <iostream>
using namespace std;
#include <string>class Person
{
// 1、公共权限
public:string p_Name;int p_Age;void getNameAge(){cout << "姓名:" << p_Name << "\\t" << "年龄:" << p_Age << endl;}
// 2、保护权限
protected:int p_Height;void getHeight(){cout << "身高:" << p_Height << endl;}
// 3、私有权限int p_Idcard;void getIdcard(){cout << "身份证号:" << p_Idcard << endl;}
};int main() {// 实例化具体对象Person p1;// 1、访问公共权限类信息p1.p_Name = "张三李四";p1.p_Age = 18;p1.getNameAge();// 2、访问保护权限类信息。类外不能访问//p1.p_Height = 160;//p1.getHeight();// 3、访问私有权限类信息。类外不能访问//p1.p_Idcard = 1234567890;//p1.getIdcard();system("pause");return 0;
}
- 输出结果:
姓名:张三李四 年龄:18
请按任意键继续. . .
4.C++中struct和class的区别
C++中struct和class唯一的区别
在于默认的访问权限不同
- struct默认权限为公共权限
- class默认权限为私有权限
- 代码演示:
#include <iostream>
using namespace std;// struct默认为公共权限
struct Person
{// 属性int p_Age;// 行为void getAge(){cout << "年龄:" << p_Age << endl;}
};// class默认为私有权限
class Car
{// 属性int c_Id;// 行为void getId(){cout << "车牌号:" << c_Id << endl;}
};int main() {// 创建类对象Person p1;Car c1;p1.p_Age = 18;p1.getAge();// class创建的类默认权限为私有权限,内外不能访问//c1.c_Id;//c1.getId();system("pause");return 0;
}
- 输出结果:
年龄:18
请按任意键继续. . .
5.成员属性私有化
成员属性设置为私有的优点:
- 将所有成员属性设置为私有,可以控制读写权限
- 对于写权限,我们可以检测数据的有效性
优点一:将所有成员属性设置为私有,可以控制读写权限
- 优点一代码演示:
#include <iostream>
using namespace std;
#include <string>class Person
{
public:// 姓名可读可写void setName(string name){p_Name = name;}void getName(){cout << "姓名:" << p_Name << endl;}// 年龄只读void getAge(){p_Age = 0;cout << "年龄:" << p_Age << endl;}// 身份证信息只写void setIdcard(int idcard){p_Idcard = idcard;}private:string p_Name;int p_Age;int p_Idcard;
};int main() {Person p1;// 姓名可读可写p1.setName("张三李四");p1.getName();// 年龄只读p1.getAge();// p1.p_Age = 18; // 年龄只读不能写// 身份证号只写不可读p1.setIdcard(1234567890);// p1.setIdcard(); //身份证号只可写不可读system("pause");return 0;
}
- 输出结果:
姓名:张三李四
年龄:0
请按任意键继续. . .
优点二:对于写权限,我们可以检测数据的有效性
- 代码演示:
#include <iostream>
using namespace std;
#include <string>class Person
{
public:void setAge(int age){if (age < 0 || age > 120) // 写权限,用来检测数据的有效性{cout << "年龄超过正常人范围!" << endl;return;}p_Age = age;}void getAge(){//p_Age = 0;cout << "年龄:" << p_Age << endl;}
private:int p_Age;
};int main() {Person p1;p1.setAge(100);p1.getAge();system("pause");return 0;
}
- 输出结果:
年龄:100
请按任意键继续. . .【注】:若年龄超过120岁或者小于0岁,将会输出“年龄超过正常人的范围!,并且年龄出现乱码”
6.设计案例1-立方体类
案例描述:设计立方体类(Cube)求出立方体的面积和体积,分别用全局函数和成员函数判断两个立方体是否相等。
实现分析:
立方体相等,通过条件长宽高都相等即可判断出来,一种是利用全局函数来进行判断;另一种是利用成员函数来进行判断。
- 代码实现:
#include <iostream>
using namespace std;class Cube
{
public:void setL(int l) //设置长宽高{c_L = l;}void setW(int w){c_W = w;}void setH(int h){c_H = h;}int getL() //获取长宽高{return c_L;}int getW(){return c_W;}int getH(){return c_H;}int getZC() //获取周长{return 2*(c_L * c_W + c_L * c_H + c_W * c_H);}int getV() //获取体积{return c_L * c_W * c_H;}// 2、利用成员函数来判断立方体是否相等(只需要传入一个参数)bool isSample0(Cube &c_l_1){cout << "2、调用成员函数来判断两个立方体是否相等!" << endl;if (c_l_1.getL() == getL() && c_l_1.getW() == getW() && c_l_1.getH() == getH()){cout << "(1)两个立方体相等!" << endl;return true;}cout << "(2)两个立方体不相等!" << endl;return false;}private:int c_L; //长int c_W; //宽int c_H; //高
};// 1、利用全局函数来判断两个立方体是否相等(需要传入两个参数)
bool isSample(Cube &c_g_1,Cube &c_g_2)
{cout << "1、调用全局函数来判断两个立方体是否相等!" << endl;if (c_g_1.getL() == c_g_2.getL() && c_g_1.getW() == c_g_2.getW() && c_g_1.getH() == c_g_2.getH()){cout << "(1)两个立方体相等!" << endl;return true;}cout << "(2)两个立方体不相等!" << endl;return false;
}void test()
{Cube c1;c1.setL(10);c1.setW(10);c1.setH(10);cout << "正方体c1的周长为:" << c1.getZC() << endl;cout << "正方体c1的体积为:" << c1.getV() << endl;Cube c2;c2.setL(10);c2.setW(9);c2.setH(11);cout << "正方体c2的周长为:" << c2.getZC() << endl;cout << "正方体c2的体积为:" << c2.getV() << endl;Cube c3;c3.setL(10);c3.setW(9);c3.setH(11);cout << "正方体c3的周长为:" << c3.getZC() << endl;cout << "正方体c3的体积为:" << c3.getV() << endl;isSample(c1,c2); //调用全局函数c2.isSample0(c3); //调用成员函数
}int main() {test();system("pause");return 0;
}
- 输出结果:
正方体c1的周长为:600
正方体c1的体积为:1000
正方体c2的周长为:598
正方体c2的体积为:990
正方体c3的周长为:598
正方体c3的体积为:990
1、调用全局函数来判断两个立方体是否相等!
(2)两个立方体不相等!
2、调用成员函数来判断两个立方体是否相等!
(1)两个立方体相等!
请按任意键继续. . .
此案例实现的关键在于第二步,分别利用全局函数与局部函数来判断两个立方体是否相等。利用全局函数实现与利用局部函数实现两者是有差别的。
7.设计案例2-点和圆的关系
案例描述:设计圆形类(Circle),和一个点类(Point)求出点和圆的关系
实现分析:
(p_x,p_y)到圆心(c_x,c_y)的距离pc_l
pc_l == c_r 点在圆上;
pc_l < c_r 点在圆内;
pc_l > c_r 点在圆外;
代码实现思路:
1、常规思路,写两个类(点类和圆类),写成员属性和行为,然后进行位置关系的判断
2、在圆类中写入点类作其成员,然后进行位置关系的判断【在类中可以让另一个类 作为本类中的成员
】
- 思路一代码实现:
#include<iostream>
using namespace std;
// 创建圆类
class Circle
{
public:// 设置属性void setR(int r){c_R = r;}void setX(int x){c_X = x;}void setY(int y){c_Y = y;}// 获取属性int getR(){return c_R;}int getX(){return c_X;}int getY(){return c_Y;}private:int c_R;int c_X;int c_Y;
};// 创建点类
class Point
{
public:// 设置属性void setX(int x){p_X = x;}void setY(int y){p_Y = y;}// 获取属性int getX(){return p_X;}int getY(){return p_Y;}private:int p_X;int p_Y;
};void getCirclePoint(Circle &c, Point &p)
{if ((c.getX() - p.getX()) * (c.getX() - p.getX()) + (c.getY() - p.getY()) * (c.getY() - p.getY()) == c.getR() * c.getR()){cout << "点与圆的位置关系为:点在圆上" << endl;}else if ((c.getX() - p.getX()) * (c.getX() - p.getX()) + (c.getY() - p.getY()) * (c.getY() - p.getY())< c.getR() * c.getR()){cout << "点与圆的位置关系为:点在圆内" << endl;}else{cout << "点与圆的位置关系为:点在圆外" << endl;}
}int main() {Circle c1;Point p1;c1.setR(10);c1.setX(10);c1.setY(10);p1.setX(10);p1.setY(-1);getCirclePoint(c1, p1);system("pause");return 0;
}
- 输出结果:
点与圆的位置关系为:点在圆外
请按任意键继续. . .
- 思路二代码实现:
#include<iostream>
using namespace std;
//创建点类
class Point
{
public://设置属性void setX(int x){p_X = x;}void setY(int y){p_Y = y;}// 获取属性int getX(){return p_X;}int getY(){return p_Y;}private:int p_X;int p_Y;
};//创建圆类
class Circle
{
public:// 设置属性void setR(int r){c_R = r;}void setCenter(Point ¢er){c_Center = center;}// 获取属性int getR(){return c_R;}Point getCenter(){return c_Center;}private:int c_R;Point c_Center;
};void getCirclePoint(Circle &c, Point &p)
{int centerpoint_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 (centerpoint_distance == rdistance){cout << "点与圆的位置关系为:点在圆上" << endl;}else if (centerpoint_distance < rdistance){cout << "点与圆的位置关系为:点在圆内" << endl;}else{cout << "点与圆的位置关系为:点在圆外" << endl;}
}int main() {设置半径和圆心Circle c1;Point center; c1.setR(10);center.setX(10); //点center为(10,0)center.setY(0);c1.setCenter(center); //将点center设置为圆的圆心//设置点Point p1;p1.setX(10); //点为(10,9)p1.setY(9);getCirclePoint(c1,p1);system("pause");return 0;
}
- 输出结果:
点与圆的位置关系为:点在圆内
请按任意键继续. . .
当以后完成一个大型的开发时候,类比较多,不可能将所有的类都写在一个文件中,这样代码量太大了,因此可以将类进行分文件编写,这样方便管理。
1..h头文件
存放成员属性和行为的申明;
2..cpp文件
存放类函数的实现;
【注意】:
1.#pragma once
是一个比较常用的C/C++预处理指令,只要在头文件的最开始加入这条预处理指令,就能够保证头文件只被编译一次,防止头文件被重复引用。
2.Point::
与Circle::
用于申明函数的作用域,为Point类和Circle类下的成员函数
- 代码演示:
Point.h
文件
#pragma once //防止头文件重复包含
#include <iostream>
using namespace std;
class Point
{
public://设置属性void setX(int x);void setY(int y);// 获取属性int getX();int getY();
private:int p_X;int p_Y;
};
Point.cpp
文件
#include "Point.h"
//设置属性
void Point::setX(int x)
{p_X = x;
}
void Point::setY(int y)
{p_Y = y;
}
// 获取属性
int Point::getX()
{return p_X;
}
int Point::getY()
{return p_Y;
}
Circle.h
文件
#pragma once
#include <iostream>
using namespace std;
#include "Point.h" //包含Point类,因此需要包含Point类的头文件
class Circle
{
public:// 设置属性void setR(int r);void setCenter(Point& center);// 获取属性int getR();Point getCenter();private:int c_R;Point c_Center;
};
Circle.cpp
文件
#include "Circle.h"// 设置属性
void Circle::setR(int r)
{c_R = r;
}
void Circle::setCenter(Point ¢er)
{c_Center = center;
}// 获取属性
int Circle::getR()
{return c_R;
}
Point Circle::getCenter()
{return c_Center;
}
点与圆位置关系的分文件编写代码实现
设计案例2的分文件编写(主要为类的分文件编写)
.h文件写类属性、行为的申明
.cpp文件写类函数的实现
#include <iostream>
using namespace std;
#include "Circle.h"
#include "Point.h"void getCirclePoint(Circle& c, Point& p)
{int centerpoint_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 (centerpoint_distance == rdistance){cout << "点与圆的位置关系为:点在圆上" << endl;}else if (centerpoint_distance < rdistance){cout << "点与圆的位置关系为:点在圆内" << endl;}else{cout << "点与圆的位置关系为:点在圆外" << endl;}
}int main() {Circle c1;Point center;c1.setR(10);center.setX(10);center.setY(0);c1.setCenter(center);Point p1;p1.setX(10);p1.setY(9);getCirclePoint(c1, p1);system("pause");return 0;
}
- 输出结果:
点与圆的位置关系为:点在圆内
请按任意键继续. . .