视频与课件来源:https://www.bilibili.com/video/BV1et411b73Z?spm_id_from=333.337.search-card.all.click
文章目录
前言
在C++这种面向对象语言中,万事万物皆为对象,当然对象上自然有属性和行为。
C++面向对象的三大特性为:封装、继承、多态
一.概述
封装的意义:
- 将属性和行为作为一个整体,表现生活中的事物
- 将属性和行为加以权限控制
封装的意义1
在设计类的时候,属性和行为写在一起,表现事物
语法: class 类名{ 访问权限: 属性 / 行为 };
属性通常是一些变量
行为通常是一些函数
知道了属性和行为构成类后,我们就可以通过类来创建对象(实例化)
- 类中的属性和行为,统称为成员
- 属性又称成员属性或成员变量
- 行为又称成员函数或成员方法
示例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
类在设计时,可以把属性和行为放在不同的权限下,加以控制
访问权限有三种:
- public 公共权限 。类内可以访问,类外可以访问
- protected 保护权限。类内可以访问,类外不可以访问。(类外不可以访问的意是将类实例化创建对象后,这个对象不可以访问类内protected和private的成员)
- 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.函数的分文件编写
函数的分文件编写总结:
- 创建后缀名为.h的头文件
- 创建后缀名为.cpp的源文件
- 在头文件中写函数的声明
- 在源文件中写函数的定义
- 在源文件中要包含头文件(源文件也分为函数定义的源文件和包含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函数中导入需要的结构体头文件