【C++核心编程】4 类和对象-封装
黑马程序员匠心之作|C++教程从0到1入门编程
学习笔记
本阶段主要针对C++ 面向对象编程技术做详细讲解,探讨C++中的核心和精髓
C++面向对象的三大特性为:封装、继承、多态
C++认为万事万物都可以称为对象,对象有其属性和行为
例如:
人,属性:姓名、年龄…,行为:走、跑、跳…
车,属性:轮胎、方向盘…,行为:载人、放音乐…
具有相同性质的对象,我们可以抽象称为类
4.1 封装
4.1.1 封装的意义
封装的意义:
意义1 :将属性和行为作为一个整体,表现生活中的事物
语法:class 类名{ 访问权限:属性/行为};
示例1:
创建一个圆类,求圆的周长
#include<iostream>
using namespace std;
//圆周率
const double PI = 3.14;
//设计一个圆类,求圆的周长
//圆求周长:2*PI*半径
//class代表设计一个类,类后面紧跟着的就是类名称
class Circle {
//访问权限
//公共权限
public:
//属性
//半径
int m_r;
//行为
//获取圆的周长
double calculateZC() {
return 2 * PI*m_r;
}
};
int main() {
//通过圆类来创建具体的圆(对象)
//实例化 (通过一个类创建一个对象的过程)
Circle c1;
//给圆对象 的属性赋值
c1.m_r = 10;
//2*3.14*10=62.8
cout << "圆的周长为:" << c1.calculateZC() << endl;
system("pause");
return 0;
}
示例2:
设计一个学术类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号
#include<iostream>
using namespace std;
#include<string>
class Student {
public://公共权限
//属性
string name;
string number;
//行为
//显示姓名和学号
void showStudent() {
cout << "学生姓名:" << name << " 学号:" << number << endl;
}
//给姓名赋值
void setName(string setname) {
name = setname;
}
//给学号赋值
void setNumber(string setnumber) {
number = setnumber;
}
};
int main() {
//实例化对象
Student std1;
std1.name = "张三";
std1.number = "20170001";
//显示学生信息
std1.showStudent();
Student std2;
std2.setName("李四");
std2.setNumber("20170002");
//显示学生信息
std2.showStudent();
system("pause");
return 0;
}
输出:
学生姓名:张三 学号:20170001
学生姓名:李四 学号:20170002
补充:
专业术语:
类中的属性和行为,我们统一称为:成员
属性:也称为成员属性,成员变量
行为:也称为成员函数,成员方法
意义2:将属性和行为加以权限控制
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
- public 公共权限
成员 类内可以访问,类外也可以访问 - protected 保护权限
成员 类内可以访问,类外不可以访问,后面学继承的时候,儿子也可以访问父亲中的保护内容 - private 私有权限
成员 类内可以访问,类外不可以访问,继承中,儿子不可以访问父亲私有内容
示例:
#include<iostream>
using namespace std;
#include<string>
//1. public 公共权限 成员 类内可以访问,类外也可以访问
//2. protected 保护权限 成员 类内可以访问,类外不可以访问,后面学继承的时候,儿子也可以访问父亲中的保护内容
//3. private 私有权限 成员 类内可以访问,类外不可以访问,继承中,儿子不可以访问父亲私有内容
class Person{
public:
//公共权限
string m_Name;//姓名
protected:
//保护权限
string m_Car;//汽车
private:
//私有权限
int m_Password;//银行卡密码
public:
void func() {
m_Name = "张三";
m_Car = "拖拉机";
m_Password = 123456;
}
};
int main() {
//实例化具体对象
Person p1;
p1.m_Name = "李四";
//p1.m_Car = "宝马";//类外访问不了
//p1.m_Password="11"//类外不可以访问
system("pause");
return 0;
}
4.1.2 struct和class区别
区别:
struct默认权限是公共public
class默认权限是私有private
示例:
#include<iostream>
using namespace std;
#include<string>
//1. public 公共权限 成员 类内可以访问,类外也可以访问
//2. protected 保护权限 成员 类内可以访问,类外不可以访问,后面学继承的时候,儿子也可以访问父亲中的保护内容
//3. private 私有权限 成员 类内可以访问,类外不可以访问,继承中,儿子不可以访问父亲私有内容
class C1{
int m_A;//默认是私有权限
};
struct C2 {
int m_A;//默认权限是公共权限
};
int main() {
C1 c1;
// c1.m_A = 100;//报错,不可访问
C2 c2;
c2.m_A = 100;//struct默认是public
system("pause");
return 0;
}
4.1.3 成员属性设置为私有
优点1:将所有成员属性设置为私有,可以自己控制读写权限
优点2:对于写权限,我们可以检测数据的有效性
示例:
#include<iostream>
using namespace std;
#include<string>
//成员属性设置为私有
//优点1:将所有成员属性设置为私有,可以自己控制读写权限
//优点2:对于写权限,我们可以检测数据的有效性
class Person {
public:
//设置姓名
void setName(string name) {
m_Name = name;
}
//获取姓名
string getName() {
return m_Name;
}
//获取年龄 只读
int getAge() {
m_Age = 0;//初始化为0岁
return m_Age;
}
//设置 情人 只写
void setLover(string lover) {
m_Lover = lover;
}
//学号 可读可写 如果想修改,只能在0-150之间
void setNumber(int number){
if (number < 0 || number>150) {
number = 0;//强制改为0
cout << "你的输入有误" << endl;
return;
}
m_Number = number;
}
//获取学号
int getNumber() {
return m_Number;
}
private:
//姓名 可读可写
string m_Name;
//年龄 可读
int m_Age;
//情人 只写
string m_Lover;
//学号 可读可写 如果想修改,只能在0-150之间
int m_Number;
};
int main() {
Person p;
p.setName("张三");
cout << "姓名为:" << p.getName() << endl;
//p.m_Age = 18//报错 只读
cout << "年龄为:" << p.getAge() << endl;
p.setLover("苍井");
//cout << "情人为" << p.setLover() << endl;//报错,不可以访问
p.setNumber(50);
cout << "学号:" << p.getNumber() << endl;
system("pause");
return 0;
}
输出:
姓名为:张三
年龄为:0
学号:50
练习案例1:设计立方体类
设计立方体类(Cube)
求出立方体的面积和体积
分别用全局函数和成员函数判断两个立方体是否相等
示例:
#include<iostream>
using namespace std;
#include<string>
class Cube {
private://属性最好设置成private
double m_L;
double m_W;
double m_H;
//行为
public:
void setL(double l) {
m_L = l;
}
double getL() {
return m_L;
}
void setW(double w) {
m_W = w;
}
double getW() {
return m_W;
}
void setH(double h) {
m_H = h;
}
double getH() {
return m_H;
}
double getArea() {
return 2 * (m_L*m_W + m_L*m_H + m_W*m_H);
}
double getVolume() {
return m_L*m_W*m_H;
}
//成员函数判读是否相等
bool isSameByClass(Cube &c) {//传入一个参数
if (m_L== c.getL()&m_W == c.getW()&m_H == c.getH()) {
return true;
}
return false;
}
};
//全局函数判断是否相等
bool isSame(Cube &c1, Cube &c2) {//传入两个参数
if (c1.getL() == c2.getL()&c1.getW() == c2.getW()&c1.getH() == c2.getH()) {
return true;
}
return false;
}
int main() {
Cube c1;
c1.setL(1);
c1.setW(2);
c1.setH(3);
cout << "立方体c1的面积为:" << c1.getArea() << endl;
cout << "立方体c1的体积为:" << c1.getVolume() << endl;
Cube c2;
c2.setL(1);
c2.setW(2);
c2.setH(4);
cout << "立方体c2的面积为:" << c2.getArea() << endl;
cout << "立方体c2的体积为:" << c2.getVolume() << endl;
//全局函数判断
bool ret = isSame(c1, c2);
if (ret) {
cout << "运用全局函数得到相等" << endl;
}
else {
cout << "运用全局函数得到不相等" << endl;
}
//成员函数判断
ret = c1.isSameByClass(c2);
if (ret) {
cout << "运用成员函数得到相等" << endl;
}
else {
cout << "运用成员函数得到不相等" << endl;
}
system("pause");
return 0;
}
输出:
立方体c1的面积为:22
立方体c1的体积为:6
立方体c2的面积为:28
立方体c2的体积为:8
运用全局函数得到不相等
运用成员函数得到不相等
练习案例2:点和圆的关系
设计一个圆形类(Circle),和一个点类(Point),计算点和圆的关系
示例:
#include<iostream>
using namespace std;
#include<string>
class Circle {
private:
double centerX;
double centerY;
double m_r;
public:
void setCenterX(double c_x) {
centerX = c_x;
}
double getCenterX() {
return centerX;
}
void setCenterY(double c_y) {
centerY = c_y;
}
double getCenterY() {
return centerY;
}
void setR(double r) {
m_r = r;
}
double getR() {
return m_r;
}
};
class Point {
private:
double pointX;
double pointY;
public:
void setPointX(double p_x) {
pointX = p_x;
}
double getPointX() {
return pointX;
}
void setPointY(double p_y) {
pointY = p_y;
}
double getPointY() {
return pointY;
}
};
void checkLink(Circle &c,Point &p) {
double d = sqrt((p.getPointX() - c.getCenterX())*(p.getPointX() - c.getCenterX())
+ (p.getPointY() - c.getCenterY())*(p.getPointY() - c.getCenterY()));
if (d < c.getR()) {
cout << "点在圆内" << endl;
}
else if(d == c.getR()) {
cout << "点在圆上" << endl;
}
else{
cout << "点在圆外" << endl;
}
}
int main() {
Circle c;
Point p;
c.setCenterX(1.5);
c.setCenterY(2);
c.setR(3);
p.setPointX(2.5);
p.setPointY(4.5);
checkLink(c, p);
system("pause");
return 0;
}
但是,如果项目更为复杂,全部写在一起就很乱,因此我们需要将类写到其他文件里面。
- 在头文件中创建一个point.h文件
#pragma once
#include<iostream>
using namespace std;
class Point {
private:
double pointX;
double pointY;
public://只需要声明,不需要实现
void setPointX(double p_x);
double getPointX();
void setPointY(double p_y);
double getPointY();
};
- 在头文件中创建一个circle.h文件
#pragma once
#include<iostream>
using namespace std;
class Circle {
private:
double centerX;
double centerY;
double m_r;
public:
void setCenterX(double c_x);
double getCenterX();
void setCenterY(double c_y);
double getCenterY();
void setR(double r);
double getR();
};
- 在源文件中创建一个point.cpp文件
#include"point.h"
//Point拆分文件编写
void Point::setPointX(double p_x) {//Point:: Point作用域下的set函数
pointX = p_x;
}
double Point::getPointX() {
return pointX;
}
void Point::setPointY(double p_y) {
pointY = p_y;
}
double Point::getPointY() {
return pointY;
}
- 在源文件中创建一个circle.cpp文件
#include"circle.h"
//Circle拆分文件编写
void Circle::setCenterX(double c_x) {
centerX = c_x;
}
double Circle::getCenterX() {
return centerX;
}
void Circle::setCenterY(double c_y) {
centerY = c_y;
}
double Circle::getCenterY() {
return centerY;
}
void Circle::setR(double r) {
m_r = r;
}
double Circle::getR() {
return m_r;
}
- main文件
#include<iostream>
using namespace std;
#include<string>
#include"point.h"
#include"circle.h"
void checkLink(Circle &c,Point &p) {
double d = sqrt((p.getPointX() - c.getCenterX())*(p.getPointX() - c.getCenterX())
+ (p.getPointY() - c.getCenterY())*(p.getPointY() - c.getCenterY()));
if (d < c.getR()) {
cout << "点在圆内" << endl;
}
else if(d == c.getR()) {
cout << "点在圆上" << endl;
}
else{
cout << "点在圆外" << endl;
}
}
int main() {
Circle c;
Point p;
c.setCenterX(1.5);
c.setCenterY(2);
c.setR(3);
p.setPointX(2.5);
p.setPointY(4.5);
checkLink(c, p);
system("pause");
return 0;
}