C++类与对象——封装

目录

前言

一、属性的行为作为整体

1.封装的意义:

1.1封装的意义一——基本语法

1.2案例(设计一个学生类)

1.3封装的意义二——访问权限

二、class和struct的区别

三、成员属性私有化

1.好处1:控制属性的读写权限

​2.好处2:检测数据的有效性

四、案例

1.立方体类

2.点和圆的关系


前言

C++面向对象的三大特性是:封装,继承,多态(本文讲的是封装)

在C++的眼里,万事万物均为对象,对象都有属性和行为

例如:

人可以作为一个对象

属性有:姓名、年龄、身高、体重......;

行为有:跑,跳,吃饭,睡觉,唱歌,生气,开心,哭泣等......

花也可以作为一个对象

属性有:颜色,高度,种类......

行为有:发芽,生长,开花,释放花香,枯萎.......

人有各自所处的环境,包括职业,所在区域,我们都被封装在这一个存在变化的特定区域内,和一个集体一起表现出这个集体的特性,且其他集体对我们这个集体有访问权限限制

花也被封装在一个特定的环境里,或温室,或野外

这就是封装

具有相同性质的对象,我们把它归之为类,比如人属于人类,花属于花类

而人又归属于灵长类动物,所以继承自父类(灵长类)

而花又属于父类(植物类)的继承

人可以分为很多种,根据属性和行为可以分出年轻的正在跑的人,矮的正在睡觉的人......

花也可以分为很多种,红色的释放玫瑰香的花,白色的释放栀子香的花......

这就是多态

一、属性的行为作为整体

1.封装的意义:

- 将属性作为一个整体,表现生活中的事物

- 将属性和行为加以权限控制

1.1封装的意义一——基本语法

在设计类时,属性和行为写在一起,表现事物

语法class{访问权限: 属性/行为};

实例:

把圆类的属性和行为作为一个整体来体现Circle这个类

设计一个圆类,求圆的周长,代码有注释,跟着敲一遍就懂了

类和对象的关系就是,类是建筑物的蓝图,而对象是具体建造出来的建筑物,类不是一个具体的内容,我们得创建一个类的对象来获取具体的内容(获得一些实质性的东西)

类中的属性通常是一些变量比如这个例子中的double r;

类中的行为通常是一些函数比如这个例子中的:

double cirLen(r)
    {
        return 2 * pi*r;
    }

#include<iostream>
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 << "用户输入的半径计算出来的圆的周长是:"<<c.cirLen(r) << endl;
	system("pause");
	return 0;
}

输出结果是:

1.2案例(设计一个学生类)

设计一个学生类,学生的属性有姓名、学号,可以给学号和姓名赋值,也可以显示学号和姓名

如果报错说:没有与XXX相匹配的运算符,那么多半是没有包含头文件,比如我们在用到string的时候要包含一个也叫string的头文件,这样才不会报错 

#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
	//学生类的属性
	string stuNum;//学号,用字符串类型,要加上头文件#include<string>
	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<iostream>
#include<string>
using namespace std;
class Student
{
public:
	//学生类的属性
	string stuNum;//学号,用字符串类型,要加上头文件#include<string>
	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<iostream>
using namespace std;
#include<string>
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 <子类名(比如Lisa)>:权限比如public 父类名字比如Person {  };

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<iostream>
using namespace std;
#include<string>
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<iostream>
#include<string>
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<iostream>
#include<string>
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;
}

2.好处2:检测数据的有效性

我们可以对用户输入的年龄一栏加以控制,首先给age开放一个可写(set)的权限,再控制用户可以写的年龄范围(0~150岁),超出范围则提示用户输入超出范围,并且返回一个默认值0,说明用户年龄设置不成功

#include<iostream>
#include<string>
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<iostream>
#include<string>
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<iostream>
#include<string>
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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在面向对象的编程中,C语言并不直接支持类和抽象的概念。引用中提到,final关键字用来修饰方法,表示该方法不能在子类中被覆盖。而abstract关键字用来修饰抽象方法,表示该方法必须在子类中被实现。然而,在C语言中,没有对应的关键字来实现类和抽象的概念。 相反,C语言通过结构体来模拟类的概念。结构体是一种用户自定义的数据类型,可以包含多个不同类型的数据成员。通过结构体,我们可以将相关的数据和功能组合在一起。然而,C语言中的结构体不支持继承和多态等面向对象的特性。 在C语言中,我们可以使用函数指针来模拟抽象类和接口的概念。函数指针可以指向不同的函数,通过使用函数指针,我们可以实现多态性,即在运行时根据函数指针指向的具体函数来执行不同的操作。 综上所述,C语言并不直接支持面向对象中的类和抽象的概念,但可以使用结构体和函数指针来实现类似的功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [面向对象——类和对象](https://blog.csdn.net/shouyeren_st/article/details/126210622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [面向对象编程原则(06)——依赖倒转原则](https://blog.csdn.net/lfdfhl/article/details/126673771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值