C++面向对象之封装

视频与课件来源:https://www.bilibili.com/video/BV1et411b73Z?spm_id_from=333.337.search-card.all.click


前言

在C++这种面向对象语言中,万事万物皆为对象,当然对象上自然有属性和行为。

C++面向对象的三大特性为:封装、继承、多态


一.概述

封装的意义:

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制


封装的意义1

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

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

属性通常是一些变量

行为通常是一些函数

知道了属性和行为构成类后,我们就可以通过类来创建对象(实例化)

  1. 类中的属性和行为,统称为成员
  2. 属性又称成员属性或成员变量
  3. 行为又称成员函数或成员方法

示例1:设计一个圆类,求圆的周长

#include<iostream>
using namespace std;
#include<string>
#define PI 3.14
int main() {
	// 设计一个圆类,求圆的周长
	// 2*PI*2r=周长
//   圆类
	class Circle {
		// 访问权限:公共权限

	public:
		// 属性:半径

		int c_r;

		// 行为:求周长
		
		double calculateZC() {
			return 2 * PI *c_r;
		}

};
	// 通过圆类来创建具体的圆(对象)
	Circle c1;
	//给圆对象的属性和行为进行赋值
	c1.c_r = 10;
	cout << "圆的周长为:" << c1.calculateZC() << endl;


	system("pause");
	return 0;
}

在这里插入图片描述





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

#include<iostream>
using namespace std;
#include<string>
class Student {
public:
	string name;
	int num;

  void showStudent(){
	  cout << "学生名字为:" << name << "    " << "学生学号为:" << num << endl;
 }
  void setName() {
	  cout << "请输入姓名:";
     getline(cin,name);

  }
  void setNum() {
	  cout << "请输入学号:";
	 cin>>num;
	  cout << endl;

  }

};
int main() {
	Student s1;
	/*cout << "请输入学生姓名:";
	cin >> s1.name;
	cout << "请输入学生学号:";
	cin >> s1.num;	
	*/
	s1.setName();
	s1.setNum();
	s1.showStudent();








	system("pause");
	return 0;
}

在这里插入图片描述





封装的意义2

类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有三种:

  1. public 公共权限 。类内可以访问,类外可以访问
  2. protected 保护权限。类内可以访问,类外不可以访问。(类外不可以访问的意是将类实例化创建对象后,这个对象不可以访问类内protected和private的成员)
  3. private 私有权限。类内可以访问,类外不可以访问。



示例:

#include<iostream>
using namespace std;
#include<string>
//三种权限
//公共权限  public     类内可以访问  类外可以访问
//保护权限  protected  类内可以访问  类外不可以访问
//私有权限  private    类内可以访问  类外不可以访问
class Person {
	// 公共权限
public:
	string name; //姓名
	// 保护权限
protected:
	string car;  //汽车
	// 私有权限
private:
	string password; // 密码
	// 行为
public:
	void func() {
		name = "张三";
		car = "BMW";
		password = "abcdwadawd";
		cout << "姓名:" << name << "    " << "汽车名:" << car << "    " << "密码:" << password << endl;
	}

};

int main() {
	Person p1;
	p1.func();
	p1.name = "李四";
	// p1.car = "奔驰";  //保护权限访问不到
	// p1.paassword="dadadada" 私有权限访问不到


	system("pause");
	return 0;
}

在这里插入图片描述







二.struct和class区别,其实两者都可表示类

在C++中 struct和class唯一的区别就在于 默认的访问权限不同

区别:

  • struct 默认权限为公共
  • class 默认权限为私有

这说明在结构体中同样能设置成员的访问权限!!

示例:

#include<iostream>
using namespace std;
#include<string>
struct Person1 {
public:
	string name;
	string sex;
	int age;
protected:
	void func() {
		cout << "this is struc!" << endl;
	}

};
class Person2 {
	string name;
	string sex;
	int age;



};
int main() {
	Person1 p1;
	Person2 p2;
	// struct默认权限为公有权限,可访问
	p1.name = "张三";
	// p1.func(); struct中的保护权限,不可访问

	cout << p1.name << endl;
	//  p2.name = "李四"; class默认权限为私有权限,不可访问
	// cout << p2.name << endl;



}

在这里插入图片描述





三.将成员属性设置为私有

优点1:将所有成员属性设置为私有,可以自己控制读写权限

优点2:对于写权限,我们可以检测数据的有效性

示例:

#include<iostream>
using namespace std;
#include<string>
class Person {
private:
	string s_name; // 可读可写
	int s_age;    // 只读
	string s_lover; //只写
public:
	// 设置名字(可读可写)
	void setName(string name) {
		s_name = name;
	}
	// 获取名字
	string getName() {
		return s_name;
	}
	// 写一个年龄,来判断数据的有效性
	void setAge(int age) {
		if (age < 0 || age>150) {
			s_age = 0;
			cout << "输入错误!" << endl;
			return;
		}
		s_age = age;
	}
	// 年龄是只读的,只能获取
	int getAge() {
		//int age = 15;
		return s_age;
	}
	// 爱人是只写的,只能设置
	void setLover(string lover) {
		s_lover = lover;
	}

};
int main() {
	Person p1;
	p1.setName("张三");
	cout << "姓名:" << p1.getName() << endl;
	// p1.s_age;  无论是姓名还是年龄还是爱人,都是私有属性,不可访问
	//p1.setAge(1000); //检测数据准确性,1000这个年龄是错的
	p1.setAge(15);
	cout << "年龄:" << p1.getAge() << endl;






	system("pause");
	return 0;
}

在这里插入图片描述







四.练习案例

案例1

设计立方体类(Cube)

求出立方体的面积和体积

分别用全局函数和成员函数判断两个立方体是否相等。

#include<iostream>
using namespace std;
#include<string>
/*练习案例1:设计立方体类**

		设计立方体类(Cube)

		求出立方体的面积和体积

		分别用全局函数和成员函数判断两个立方体是否相等。
		*/
//  面积=2*a*b+2*b*c+2*a*c
//  体积=a*b*c
class cube {
public:
	// 比较两个立方体是否相等
	void Compare1(cube c2) {
		if (m_a == c2.getA() && m_b== c2.getB() && m_c== c2.getC()) {
			cout << "两个立方体相等!" << endl << endl;
		}
		cout << "两个立方体不相等!" << endl << endl;
	}
	// 设置长度m_a
	void setA(int a) {
		m_a = a;
	 }
	 // 设置宽度m_b
	void setB(int b) {
		m_b = b;
	}
	 // 设置高度m_c
	void setC(int c) {
		m_c = c;
	}
	//获取长度m_a
	int getA() {
		return m_a;
	 }
	// 获取宽度m_b
	 	int getB() {
	return m_b;
}
	// 获取高度m_c
		int getC() {
return m_c;
	 }
	// 获取面积
	double getSquare() {
		m_square = 2 * m_a * m_b + 2 * m_a * m_c + 2 * m_b * m_c;
		return m_square;
	}
	// 获取体积
    double getVolume() {
		m_volume = m_a * m_c * m_b;
		return m_volume;
	}
private:
	int m_a;
	int m_b;
	int m_c;
	double m_square;
	double m_volume;


};
void Compare2(cube c1,cube c2 ) {
	if (c1.getA() == c2.getA()&& c1.getB() == c2.getB() && c1.getC() == c2.getC()) {
		cout << "两个立方体相等!" << endl << endl;
		return;
	}
	cout << "两个立方体不相等!" << endl << endl;
}
int main() {
	cube c1;
	cube c2;
	c1.setA(10); c1.setB(1); c1.setC(10);
	c2.setA(1); c2.setB(10); c2.setC(10);
	cout << "第一个立方体长度:" << c1.getA() << endl;
	cout << "第一个立方体宽度:" << c1.getB () << endl;
	cout << "第一个立方体高度:" << c1.getC () << endl << endl;
	cout << "第二个立方体长度:" << c2.getA () << endl;
	cout << "第二个立方体宽度:" << c2.getB () << endl;
	cout << "第二个立方体高度:" << c2.getC () << endl << endl;
	cout << "第一个立方体的面积:" << c1.getSquare() << endl;
	cout << "第一个立方体的体积:" << c1.getVolume() << endl << endl;
	cout << "第二个立方体的面积:" << c2.getSquare() << endl;
	cout << "第二个立方体的体积:" << c2.getVolume() << endl<<endl;
	Compare2(c1, c2);
		cout << endl<<endl;
		c1.Compare1(c2);


	system("pause");
	return 0;
}

在这里插入图片描述

1.属性尽量设置为私有

2.类名可以做函数参数
例子:void Compare2(cube c1,cube c2 )
上面形参中的cube是一个类,操作c1 和c2就是操作两个cube类

3.注意:结构体和类中的属性可以有初始值,但不要用表达式去赋值,而且如果实在想给他赋值,应该用函数来赋值
比如:不要这样去给c赋值
class circle{
private:
int a=25;(√)这种简单的赋值是可以的
int b=66;(√)
string name=“waeawewae”;(√)
double square=2 * a * b;(x)错误
最好是直接写square这么一个声明,后序如果想给它赋值什么的最好用函数来封装
double square;(√)
}
用函数来赋值
double getsquare(){
return 2 * a * b;
}








再比如:
class circle{
private:
int a;
int b;
double square;
square=2 * a * b;(x)这样子不是不好,是直接报错!!
↓赋值行为还是得用函数来封装
double getsquare(){
return 2 * a * b;
}






示例2

注意:当程序中有多个类时,不要把所有类都写在一个文件中!!这就引出了分文件编写

练习案例2:点和圆的关系

设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系。

示例1:没有分文件编写

#include<iostream>
using namespace std;
#include<string>
#include<math.h>
#define PI 3.14



// 点类
class Point {
private:
	int p_left;//点横坐标
	int p_right;//点纵坐标
public:
	// 设置点横坐标
	void setLeft(int left) {
		p_left = left;
	}
	// 设置点纵坐标
	void setRight(int right) {
		p_right = right;
	}
	// 获取点横坐标
	int getLeft() {
		return p_left;
	}
	// 获取点纵坐标
	int getRight() {
		return p_right;
	}
};


// 圆类
class Circle {

private:
	int m_R;// 半径
	Point m_P;//圆心,一个类中可以包含另一个类
	double m_Square;
	double m_Girth;
public:
	// 设置半径
	void setR(int x) {
		m_R = x;

	}
	// 获取半径
	int getR() {
		return m_R;
	}
	// 设置圆心
	void setCentre(Point &p) {
		m_P = p;
	}

	// 获取圆心
	// 类可以做函数返回值
	Point getCentre() {
		return m_P;
	}

	// 得到面积
	double getSqaure() {
		m_Square = m_R * PI * m_R;
		return  m_Square;
	}
	// 得到周长
	double getGirth() {
		m_Girth = 2 * PI * m_R;
		return m_Girth;
	}


};



// 判断点与圆的关系
void Num(Circle c1, Point p1) {
	double num;
	num = sqrt(((p1.getLeft() - c1.getCentre().getLeft()) * (p1.getLeft() - c1.getCentre().getLeft())) + ((p1.getRight() - c1.getCentre().getRight()) * (p1.getRight() - c1.getCentre().getRight())));
	if (num == c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在圆上!!!" << endl << endl;
		
		return;
		
	}
	if (num < c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在园内!!!!" << endl << endl;
		
		return;
	}
	if (num > c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在圆外!!!" << endl << endl;
	
		return;
	}
	
	

}
int main() {
	Circle c1;
	Point p1,p2;
	p2.setLeft(10); p2.setRight(10);
	c1.setCentre(p2);
	c1.setR(30);
	cout << "圆的半径为:" << c1.getR() << endl;
	cout << "圆心的坐标为:" << "(" << c1.getCentre().getLeft() << "," << c1.getCentre().getRight() << ")" << endl;
	cout << "圆的面积为:" << c1.getSqaure() << endl;
	cout << "圆的周长为:" << c1.getGirth() << endl << endl;
	p1.setLeft(10); p1.setRight(30); 
	cout << "点的坐标为:" << "(" << p1.getLeft() << "," << p1.getRight() << ")" << endl << endl;
	Num(c1,p1);
	cout << endl;









	system("pause");
	return 0;
}

在这里插入图片描述

1.在类中可以让另一个类作为本类中的成员
class Point{

}


class Circle{
public:
Point m_P;}

2.类可以作函数返回值、函数的参数!!
class Point{}
Point getR(){}


void setnum(Point p1,Point p2){}





示例2:分文件编写

类和对象的分文件编写规则:
1.头文件中写类的声明,一个类对应一个头文件
2.源文件中写类的实现,一个类对应一个源文件
3.当然还要有个包含main函数的源文件

#pragma once
#include<iostream>
using namespace std;
#include<string>
class Point {
private:
	int p_left;//点横坐标
	int p_right;//点纵坐标
public:
	// 设置点横坐标
	void setLeft(int left);
		
	// 设置点纵坐标
	void setRight(int right);
		
	// 获取点横坐标
	int getLeft();

		// 获取点纵坐标
		int getRight();
	
}; 

在这里插入图片描述







#pragma once
#include<iostream>
using namespace std;
#include"point.h"
#define PI 3.14
class Circle {
private:
	int c_r;//半径
	double c_sqaure;//面积
	double c_girth;//周长
	
	Point c_centre;
public:
	 // 设置圆坐标
	void setCentre(Point p1);
		
	// 获取圆心
	Point getCentre();
		
	//设置半径
	void setR(int r);
		
	// 得到半径
	int getR();
		
	// 得到面积
	double getSqaure();
		
	// 得到周长
	double getGirth();
		

};

在这里插入图片描述





#include"point.h"
#include<iostream>
using namespace std;

	// 设置点横坐标
	void Point::setLeft(int left) {
		p_left = left;
	}
	// 设置点纵坐标
	void Point::setRight(int right) {
		p_right = right;
	}
	// 获取点横坐标
	int Point::getLeft() {
		return p_left;
	}
	// 获取点纵坐标
	int Point::getRight() {
		return p_right;
	}

在这里插入图片描述

函数返回类型 类名:: 函数名(参数)





#include"circle.h"

 // 设置圆坐标
void Circle::setCentre(Point p1) {
	c_centre = p1;
}
// 获取圆心
Point Circle::getCentre() {
	return c_centre;
}
//设置半径
void Circle::setR(int r) {
	c_r = r;
}
// 得到半径
int Circle::getR() {
	return c_r;
}
// 得到面积
double Circle::getSqaure() {
	c_sqaure = c_r * PI * c_r;
	return c_sqaure;
}
// 得到周长
double Circle::getGirth() {
	c_girth = 2 * PI * c_r;
	return c_girth;
}


在这里插入图片描述

函数返回类型 类名:: 函数名(参数)





#include<iostream>
using namespace std;
#include<string>
#include<math.h>
#include"circle.h"
#include"point.h"






void Num(Circle c1, Point p1) {
	double num;
	//c1.setCentre(p2);
	num = sqrt(((p1.getLeft() - c1.getCentre().getLeft()) * (p1.getLeft() - c1.getCentre().getLeft())) + ((p1.getRight() - c1.getCentre().getRight()) * (p1.getRight() - c1.getCentre().getRight())));
	if (num == c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在圆上!!!" << endl << endl;

		return;

	}
	if (num < c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在园内!!!!" << endl << endl;

		return;
	}
	if (num > c1.getR()) {
		cout << "点到圆心的距离为:" << num << endl << endl;
		cout << "点在圆外!!!" << endl << endl;

		return;
	}



}





int main() {
	Circle c1;
	Point p1, p2;
	p2.setLeft(10); p2.setRight(10);
	c1.setCentre(p2);
	c1.setR(30);
	cout << "圆的半径为:" << c1.getR() << endl;
	cout << "圆心的坐标为:" << "(" << c1.getCentre().getLeft() << "," << c1.getCentre().getRight() << ")" << endl;
	cout << "圆的面积为:" << c1.getSqaure() << endl;
	cout << "圆的周长为:" << c1.getGirth() << endl << endl;
	p1.setLeft(10); p1.setRight(30);
	cout << "点的坐标为:" << "(" << p1.getLeft() << "," << p1.getRight() << ")" << endl << endl;
	Num(c1, p1);
	cout << endl;







	system("pause");
	return 0;
}


在这里插入图片描述
在这里插入图片描述










五.分文件编写总结

1.函数的分文件编写

函数的分文件编写总结:

  1. 创建后缀名为.h的头文件
  2. 创建后缀名为.cpp的源文件
  3. 在头文件中写函数的声明
  4. 在源文件中写函数的定义
  5. 在源文件中要包含头文件(源文件也分为函数定义的源文件和包含main函数的源文件)

示例

//swap.h文件
#pragma once //防止头文件重复包含
#include<iostream>
using namespace std;
注意以上三句是头文件的标准模板,绝不可以少。

//实现两个数字交换的函数声明
void swap(int a, int b);
//swap.cpp文件
#include "swap.h"
// “ ”双引号代表这个文件是自定义文件
void swap(int a, int b)
{
	int temp = a;
	a = b;
	b = temp;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
}
//main函数文件
#include "swap.h"
int main() {

	int a = 100;
	int b = 200;
	swap(a, b);

	system("pause");

	return 0;
}

在这里插入图片描述



在这里插入图片描述





在这里插入图片描述





在这里插入图片描述






2.类和对象的分文件编写

类和对象的分文件编写规则:
1.头文件中写类的声明,一个类对应一个头文件
2.源文件中去掉大部分框架,只需写类的实现(记得加作用域),一个类对应一个源文件
3.当然还要有个包含main函数的源文件





3.结构体的分文件编写

结构体的分文件编写和类和对象的差不多,因为结构体可以代替类
1.创建头文件源文件
2.头文件写声明,源文件写实现
3.如果结构体中就一些属性的话,源文件都不需要写
4.main函数中导入需要的结构体头文件
在这里插入图片描述



在这里插入图片描述



在这里插入图片描述



在这里插入图片描述



在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值