Day 09 C++面向对象编程 之 封装

C++面向对象的三大特征为:封装、继承、多态。C++认为万事万物都皆为对象,对象上有其属性和行为。例如:

  • 人可以作为对象,属性包含姓名、性别、年龄、身高、体重…,行为有走、跑、跳、吃饭、喝水…
  • 车也可以作为对象,属性包含轮胎、方向盘、车灯…行为有载人、放音乐、放空调…

具有相同性质的对象,我们可以抽象为类,人属于人类,车属于车类。

一、封装的意义

封装是C++面向对象的三大特征之一。封装的意义:

  • 将属性和行为作为一个整体,表现生活中的事物(对象)
  • 将属性和行为加以权限控制
1.封装意义一:对象

在设计类的时候,属性和行为写在一起,表现为事物。语法:class 类名{ 访问权限:属性 / 行为};

例子1:设计一个圆类
求圆的周长
const double PI = 3.14;

class Circle
{
public:
	//属性
	int r;//半径
	
    //行为,通常使用函数表达
	double calculateZC()//求圆的周长
	{
		return 2 * PI * r;
	}
};
int main()
{
	//通过类创建这个类下的具体的事物(对象)
	Circle c1;
	//给圆的对象的属性进行赋值
	c1.r = 3;
	//调用圆的行为
	cout << "圆的周长为:" << c1.calculateZC() << endl;
	system("pause");
	return 0;
}

class 表示要设计一个类,类后面加类的名字,然后再在体内写属性 + 行为。属性同时使用变量表达,行为通常使用函数表达。类设计完成后要在主函数中创建这个类的一个对象(这个过程叫实例化),语法:类名 对象名。然后可以对对象中的属性进行赋值,语法:对象名 . 属性名 = 值。进行对象的行为,就是直接调用类中的行为函数。

例子2:设计一个学生类,

属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号

class Student
{
	//公共权限
public:
	//属性
	string name;//姓名
	string id;//学号
	//行为
	//显示姓名和学号
	void showStudent()
	{
		cout << "学生信息为:" << name << "   " << id << endl;		
	}
};
int main()
{
	...
	//创建一个学生的对象(实例化)
	Student s1;
	//对对象s1的属性进行赋值
	s1.name = "懒羊羊";
	s1.id = "123123";
	//显示学生信息
	s1.showStudent();
	system("pause");
	return 0;
}

可以将赋值操作写为行为:

//给姓名赋值
void setName(string name1)
{
    name = name1;
}
//给学号赋值
void setId(string id1)
{
	id = id1;
}
//主函数中赋值就是
s1.setName("懒羊羊");
s1.setId("123123");

类中的属性和行为统一称为成员,属性也称为成员属性或成员变量;类中的行为叫成员函数或成员方法。

2.封装意义二:权限控制

在类设计时,可以把属性和行为放在不同的权限下,加以控制。访问权限有三种:

  • public 公共权限:成员,类内 + 类外都可以访问
  • protected 保护权限:成员,类内可以访问,类外不可以访问
  • private 私有权限:成员,类内可以访问,类外不可以访问

保护权限和私有权限的区别,在继承中有所体现,继承需要二者有父子关系,其中若是保护权限,则子类可以继承,但是若是私有权限的内容,子类不可以继承。

class Person
{
public://共有权限
	string name;
protected://保护权限
	string car;
private://私有权限
	int password;
public:
	void func()
	{//类内都可以访问
		name = "懒羊羊";
		car = "宝马";
		password = 123123;
	}
};
int main()
{
	...
	Person p1;
	p1.name = "喜羊羊";
	//p1.car = "奔驰";错误,类外访问不到
	//p1.password = 789789;错误,类外访问不到,不可以访问
	system("pause");
	return 0;
}

在这里插入图片描述

二、struct 和 class 的区别

在C++中struct 和class唯一的区别就在于默认的访问权限不同。区别:struct 默认权限为公有;class 默认权限为私有

class C1
{
	int A;//未设置权限,默认为私有,类外不可以访问
};
struct C2
{
	int A;//默认为公共权限,可以访问
};

当权限没有写的时候就会设定为默认权限。

三、成员属性设置为私有

优点:

  • 将所有成员属性设置为私有,可以自己控制读写权限;
  • 对于写权限,可以检测数据的有效性
class Person
{
public:
	//设置姓名
	void setName(string name1)
	{
		name = name1;
	}
	//获取姓名
	string getName()
	{
		return name;
	}
    //设置年龄,但是必须在0-150之间,检测数据有效性
	void setAge(int age1)
	{
		if (age1 > 0 && age1 < 150)
		{
			age = age1;
		}
		else
		{
			cout << "年龄有误" << endl;
			return;
		}
	}
    //获取年龄
	int getAge()
	{
		return age;
	}
    //设置偶像
	void setIdol(string idol1)
	{
		idol = idol1;
	}
private:
	string name;//姓名  可读可写
	int age = 18;//年龄  只读
	string idol;//偶像  只写
};
int main()
{
...
	Person p;
	p.setName ("懒羊羊");//设置,写
	cout << p.getName() << endl;//访问,读
    p.setAge(13);//写
    cout << p.getAge() << endl;//访问,读
    p.setIdol("喜羊羊");//设置,写
	system("pause");
	return 0;
}
例子3:设计立方体类

设计立方体类(Cube);求出立方体的面积和体积;分别用全局函数和成员函数判断两个立方体是否相等。

class Cube
{
public:
	//设置长宽高,获取长宽高
	void setLength(int L)
	{
		m_L = L;
	}
	int getLength()
	{
		return m_L;
	}
	void setWideth(int M)
	{
		m_M = M;
	}
	int getWideth()
	{
		return m_M;
	}
	void setHight(int H)
	{
		m_H = H;
	}
	int getHight()
	{
		return m_H;
	}
	//设置行为
	//获取体积
	int calculateSV()
	{
		return m_L * m_M * m_H;
	}
	//获取面积
	int calculateSS()
	{
		int s = 0;
		s = m_L * m_M * 2 + m_L * m_H * 2 + m_M * m_H * 2;
		return s;
	}
	//成员函数判断
	bool isSame01(Cube &c)//本身调用时,已经有自己的值,只需要带入第二个立方体的参数即可
	{
		if (m_H == c.getHight() && m_L == c.getLength() && m_M == c.getWideth())
		{
			return true;
		}
		return false;
	}
private:
	//设置属性
	int m_L;//长
	int m_M;//宽
	int m_H;//高
};
//全局函数判断
bool isSame(Cube &c1, Cube &c2)//节省空间,不拷贝,直接用原来的空间的值
{
	if (c1.getHight() == c2.getHight() && c1.getLength() == c2.getLength() && c1.getWideth() == c2.getWideth())
	{
		return true;
	}
	return false;
}
int main()
{
	Cube c1;
	Cube c2;
	c1.setLength(7);
	c1.setWideth(7);
	c1.setHight(6);
	cout << "c1的面积为:" << c1.calculateSS() << endl;
	cout<< "c1的体积为:" << c1.calculateSV() << endl;

	c2.setLength(7);
	c2.setWideth(7);
	c2.setHight(8);
	bool i = isSame(c1, c2);
	if (i)//全局函数判断
	{
		cout << "全局函数判断:相同" << endl;
	}
	else
	{
		cout << "全局函数判断:不相同" << endl;
	}
	//成员函数判断
	i = c1.isSame01(c2);
    if (i)//成员函数判断
	{
		cout << "成员函数判断:相同" << endl;
	}
	else
	{
		cout << "成员函数判断:不相同" << endl;
	}
	system("pause");
	return 0;
}
例子4:点和圆的关系

设计一个圆形类(circle),和一个点类(point),计算点和圆的关系(圆外、圆上、圆内)

思路:看点和圆心的距离与半径相比

class Point
{
public:
	void setX(int x1)
	{
		x = x1;
	}
	int getX()
	{
		return x;
	}
	void setY(int y1)
	{
		y = y1;
	}
	int getY()
	{
		return y;
	}
private:
	int x;
	int y;
};
class Circle
{
public:
	void setR(int r1)
	{
		r = r1;
	}
	int getR()
	{
		return r;
	}
	void setCenter(Point p1)
	{
		center = p1;
	}
	Point getCenter()
	{
		return center;
	}
private:
	int r;
	Point center;
};
//判断圆和点的关系
void idInCircle(Circle& c, Point& p)
{
	int 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 (distance == rDistance)
	{
		cout << "点在圆上" << endl;
	}
	else if(distance > rDistance)
	{
		cout << "点在圆外" << endl;
	}
	else
	{
		cout << "点在圆内" << endl;
	}
}
int main()
{
	Circle c1;
	c1.setR(7);
	Point p1;
	Point p2;
	p1.setX(5);
	p1.setY(5);
	c1.setCenter(p1);
	p2.setX(8);
	p2.setY(16);
	idInCircle(c1, p2);
	system("pause");
	return 0;
}

类中可以用另一个类做为这个类的成员变量;通常会把一个类写在另一个文件中,避免主文件代码过多复杂:

在源文件中创建一个头文件.h,在源文件中创建一个源文件。

头文件中写入.h:point.h

#pragma once
#include<iostream>
using namespace std;
//写类的声明
class Point
{
public:
	void setX(int x1);
	
	int getX();
	
	void setY(int y1);
	
	int getY();
	
private:
	int x;
	int y;
};

源文件中写入.cpp:point.cpp

#include "point.h"

void Point::setX(int x1)//需要告诉编译器这是Point类的成员变量
{
    x = x1;
}
int Point::getX()
{
    return x;
}
void Point::setY(int y1)
{
    y = y1;
}
int Point::getY()
{
    return y;
}

若一个类中有使用其他的类,需要在前面include。若要在主函数中使用类,直接include头文件即可。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐