一、面向对象程序设计的基本特点
1.1 抽象
-
指对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程
-
数据抽象
- 描述某类对象的属性或状态,即此类对象与其他类对象的区别
-
行为抽象
-
描述某类对象的共同行为或功能特征
以人为例,对其进行抽象。
共同属性:姓名、性别、年龄等等,则数据抽象:string name, string sex, int age
共同的行为:吃饭、走路、学习等等,则行为抽象:
eat(), walk(), study()
-
1.2 C++面向对象三大特性
- 封装:将数据和操作数据的函数代码进行有机结合,形成 “ 类 ”,其中的数据和函数都是类的成员
- 继承:允许在保存原有类特性的基础上,进行更具体、更详细的说明
- 多态:一段程序能处理多种类型对象的能力
二、类和对象的基本概念
2.1 封装
-
目的:
-
增强安全性和简化编程,使用者不需要具体了解实现细节,只需要通过外部接口,以特定的权限进行访问,使用类的成员
-
意义:
- 将属性和行为作为一个整体
- 将属性和行为加以权限控制
-
语法:
class ClassName { 访问权限: 属性 行为 }
2.2 类和对象
- 类(class)
- 对逻辑上相关的函数和数据的封装,是对问题的抽象描述
- 在面向对象程序设计中,程序模块是由类构成的
- 对象(object)
- 是具有class类型的变量
- C++认为万事万物皆为对象,对象具有属性 和行为
- 具有相同性质的对象,可以抽象为类
- 例如,人属于人类,人作为对象,属性包括姓名、性别、年龄等,行为包括吃饭、走路、学习等
- 类中的属性和行为,统称为成员
- 属性:成员属性,成员变量
- 行为:成员函数,成员方法
- 创建对象的过程叫实例化,新创建的对象叫实例(instance)
2.3 类的定义
2.3.1 语法
// 类名称通常将首字母写成大写
class 类名{
public:
公有成员(外部接口) // 任何外部函数都可访问
private:
私有成员 // 只允许本类中的函数访问
protected:
保护型成员 // 与继承有关
}
// 实例化一个对象
类名 对象名;
// 访问数据成员
对象名.数据成员名
// 调用函数成员
对象名.函数成员名(参数表)
示例:
// 封装一个圆类,求圆的面积和周长
class Circle{
public:
// 属性:半径
int radius;
// 行为:获取圆面积;获取圆周长
double findArea();
double findPerimeter();
};
int main(){
Circle c;
c.radius = 10;
std::cout << "圆的面积:" << c.findArea() << std::endl;
std::cout << "圆的周长:" << c.findPerimeter() << std::endl;
}
2.3.2 成员访问权限
- public、protected和private是访问权限修饰符。
- 被public修饰的属性和函数可以在类内部与类外部被访问
- 被protected和private修饰的属性和函数只能在类内部被访问
- 成员函数可以访问本类中任何成员。一般的做法是将需要被外界调用的成员函数指定为public,他们是类的对外接口
- 有的函数并不是准备为外界调用的,而是为本类中的成员函数所调用的,就应该将它们指定为private
- 一般将属性定义为私有,行为定义为公有
- struct和class的区别:默认的访问权限不同
- struct 默认权限为公共
- class 默认权限为私有
示例:
class Clock{
public:
void setTime(int newH, int newM, int newS);
void showTime();
private:
int hour, minute, second;
}
2.3.3 类的成员函数
-
描述类的行为,对封装的数据进行操作的方法
-
函数的原型声明要写在类体中,函数的具体实现写在类定义外
-
类成员函数的默认值,一定要写在类定义中
-
语法:
返回值类型 类名::函数成员名(参数表){ 函数体 }
示例:
#include <iostream> using namespace std; class Clock { public: void setTime(int newH = 0, int newM = 0, int newS = 0); void showTime(); private: int hour, minute, second; }; // 类成员函数setTime void Clock::setTime(int newH, int newM, int newS) { hour = newH; minute = newM; second = newS; } // 类成员函数showTime void Clock::showTime() { cout << hour << ":" << minute << ":" << second; } int main() { Clock myClock; // 定义对象 myClock.setTime(8, 30, 30); // 通过“.”操作符实现对象成员函数的访问 myClock.showTime(); return 0; }
2.4 多文件编写代码
2.4.1 多文件结构
通常一个项目至少划分为3个文件:
- 类定义文件(*.h文件)
- 写类的声明,包括了所有函数的函数头
- 类实现文件(*.cpp文件)
- 写类的定义
- 注意要引用类定义文件,
#include *.h
- 定义成员函数时函数名称前要加上类名:
类名::函数
,例如:Clock::setTime
- 类使用文件(*.cpp,主函数文件)
- 创建类对象并进行调用
- 注意要引用类定义文件,
#include *.h
更为复杂的程序,可以将每一个类都用单独的定义和实现文件
2.4.2 例子:点和圆的关系
-
所有代码在同一个源文件内
# include <iostream> using namespace std; class Point { //点类 public: void setX(int x) { m_X = x; } //设置x int getX() { return m_X; } //获取x void setY(int y) { m_Y = y; } //设置y int getY() { return m_Y; } //获取y private: int m_X; int m_Y; }; class Circle { //圆类 public: void setR(int r) { m_R = r; } //设置半径 int getR(){ return m_R; } //获取半径 void setCenter(Point center){ m_Center = center; } //设置圆心 Point getCenter(){ return m_Center; } //获取圆心 private: int m_R; //半径 // //在类中可以让另一个类作为本类的成员 // Point m_Center; //圆心 }; //判断点和圆的关系 void isInCircle(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 c; c.setR(10); Point center; center.setX(10); center.setY(0); c.setCenter(center); //创建点 Point p; p.setX(10); p.setY(10); //判断关系 isInCircle(c, p); }
-
多文件编写
-
点类头文件point.h(写点类的类声明)
# pragma once # include <iostream> using namespace std; class Point { //点类 public: void setX(int x); //设置x int getX(); //获取x void setY(int y); //设置y int getY(); //获取y private: int m_X; int m_Y; };
-
点类源文件point.cpp(写点类的类定义)
# include "point.h" //设置x void Point::setX(int x) { m_X = x; } //获取x int Point::getX() { return m_X; } //设置y void Point::setY(int y) { m_Y = y; } //获取y int Point::getY() { return m_Y; }
-
圆类头文件circle.h(写圆类的类声明)
# pragma once # include <iostream> using namespace std; class Circle { //圆类 public: void setR(int r) { m_R = r; } //设置半径 int getR(){ return m_R; } //获取半径 void setCenter(Point center){ m_Center = center; } //设置圆心 Point getCenter(){ return m_Center; } //获取圆心 private: int m_R; //半径 Point m_Center; //圆心 };
-
圆类源文件circle.cpp(写圆类的类定义)
# include "circle.h" //设置半径 void Circle::setR(int r){ m_R = r; } //获取半径 int Circle::getR(){ return m_R; } //设置圆心 void Circle::setCenter(Point center){ m_Center = center; } //获取圆心 Point Circle::getCenter(){ return m_Center; }
-
主函数main.cpp(调用类)
# include <iostream> # include "circle.h" # include "point.h" using namespace std; //判断点和圆的关系 void isInCircle(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 c; c.setR(10); Point center; center.setX(10); center.setY(0); c.setCenter(center); //创建点 Point p; p.setX(10); p.setY(10); //判断关系 isInCircle(c, p); }
-
三、结构体
3.1 结构体和类的区别
- 二者基本没有区别,唯一的区别就是struct的成员的访问控制默认是pubilc,而class默认是private
- C++中结构体存在的唯一原因是想要维持与C之间的兼容性
3.2 定义和使用
- 结构体struct是用户自定义的数据类型,允许用户存储不同的数据类型
- 语法:
struct 结构体名 { 结构体成员列表 };
- 结构体变量创建方式:
- struct 结构体名 变量名
- struct 结构体名 变量名 = { 成员1值 , 成员2值…}
- 定义结构体时顺便创建变量
- 结构体变量利用操作符 “ . ” 访问成员
//结构体定义
struct student {
//成员列表
string name; //姓名
int age; //年龄
int score; //分数
} stu3; //结构体变量创建方式3
int main() {
//结构体变量创建方式1
struct student stu1; //struct 关键字可以省略
stu1.name = "张三";
stu1.age = 18;
stu1.score = 100;
cout << "姓名:" << stu1.name << " 年龄:" << stu1.age << " 分数:" << stu1.score << endl;
//结构体变量创建方式2
struct student stu2 = { "李四", 19, 60 };
cout << "姓名:" << stu2.name << " 年龄:" << stu2.age << " 分数:" << stu2.score << endl;
//结构体变量创建方式3, 定义结构体时顺便创建变量stu3
stu3.name = "王五";
stu3.age = 18;
stu3.score = 80;
cout << "姓名:" << stu3.name << " 年龄:" << stu3.age << " 分数:" << stu3.score << endl;
return 0;
}
3.3 结构体数组
- 将自定义的结构体放入到数组中方便维护
- 语法:
struct 结构体名 数组名[元素个数] = { {} , {} , ... {} };
//结构体定义
struct student {
string name; //姓名
int age; //年龄
int score; //分数
};
int main() {
//结构体数组
struct student arr[3] = {
{"张三", 18, 80 },
{"李四", 19, 60 },
{"王五", 20, 70 }
};
for (int i = 0; i < 3; i++) {
cout << "姓名:" << arr[i].name << " 年龄:" << arr[i].age << " 分数:" << arr[i].score << endl;
}
return 0;
}
3.4 结构体指针
- 通过指针访问结构体中的成员
- 利用操作符
->
可以通过结构体指针访问结构体属性
struct student {
string name; //姓名
int age; //年龄
int score; //分数
};
int main() {
struct student stu = { "张三", 18, 100 };
struct student * p = &stu;
p->score = 80; //指针通过 -> 操作符可以访问成员
cout << "姓名:" << p->name << " 年龄:" << p->age << " 分数:" << p->score << endl;
return 0;
}
3.5 结构体嵌套
//学生结构体定义
struct student {
string name; //姓名
int age; //年龄
int score; //分数
};
//教师结构体定义
struct teacher {
int id; //职工编号
string name; //教师姓名
int age; //教师年龄
struct student stu; //子结构体 学生
};
int main() {
struct teacher t1;
t1.id = 10000;
t1.name = "老王";
t1.age = 40;
t1.stu.name = "张三";
t1.stu.age = 18;
t1.stu.score = 100;
cout << "教师 职工编号: " << t1.id << " 姓名: " << t1.name << " 年龄: " << t1.age << endl;
cout << "辅导学员 姓名: " << t1.stu.name << " 年龄:" << t1.stu.age << " 考试分数: " << t1.stu.score << endl;
return 0;
}
3.6 结构体做函数参数
- 将结构体作为参数向函数中传递
- 值传递和地址传递两种方式
//学生结构体定义
struct student {
string name; //姓名
int age; //年龄
int score; //分数
};
//值传递
void printStudent(student stu) {
stu.age = 28;
cout << "子函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
}
//地址传递
void printStudent2(student *stu) {
stu->age = 28;
cout << "子函数中 姓名:" << stu->name << " 年龄: " << stu->age << " 分数:" << stu->score << endl;
}
int main() {
student stu = { "张三",18,100};
//值传递
printStudent(stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
//地址传递
printStudent2(&stu);
cout << "主函数中 姓名:" << stu.name << " 年龄: " << stu.age << " 分数:" << stu.score << endl;
return 0;
}
3.7 const
- 用const来防止误操作
struct student {
string name; //姓名
int age; //年龄
int score; //分数
};
//const使用场景
//加const防止函数体中的误操作
void printStudent(const student *stu) {
//stu->age = 100; //操作失败,因为加了const修饰
cout << "姓名:" << stu->name << " 年龄:" << stu->age << " 分数:" << stu->score << endl;
}
int main() {
student stu = { "张三",18,100 };
printStudent(&stu);
return 0;
}