本篇要学习的内容和知识结构概览
知识点逐条分析
结构的演化
C++ 中的类是从结构演变而来的, 所以我们可以称 C++ 为 "带类的 C".
结构发生质的演变
C++ 结构中可以定义函数, 称之为成员函数
结构定义格式, 像这样:
struct 结构名 {
数据成员;
成员函数;
}; // 注意这里的分号不要忘记
具体的代码, 像这样:
- struct Point {
- private:
- // 数据成员
- double x;
- double y;
- public:
- // 成员函数: 重新设置数据成员
- void setXY(double a, double b) {
- x = a;
- y = b;
- }
- // 成员函数: 指定格式输出数据成员
- void display() {
- cout <<x << "\t" << y << endl;
- }
- }; // 不要忘记分号
模型图是这样的:
它表明: 我定义了一个结构体, 有两个私有的数据成员 x, y, 两个公有的成员函数 setXY(double, x, double y), display();
在定义结构体时, 将数据成员使用 private 关键字修饰, 则产生封装性. 如果没有没定, 则默认为 public
private 修饰的数据成员为私有的数据成员, 必须公有的成员函数才能使用, 这就是数据的封装性.
使用方式: 结构对象. 成员函数
我们在 main 函数中这样使用:
- // 创建结构对象
- Point pointA;
- // 调用成员函数
- pointA.setXY(1.2, 3.4);
- // 显示 pointA 的数据成员
- pointA.display();
注意:
如果结构的数据成员用 private 关键字修饰
则不能这么访问:
cout << pointA.x << endl; count << pointA.y << endl;
如果 public 修饰, 则可以这么访问.
不过我们一般为了保证封装性, 将数据成员声明为 private, 保证只有成员函数才能访问.
使用构造函数初始化结构对象
函数名与结构同名, 称为构造函数, 专门用于初始化结构对象
分为有参构造函数和无参构造函数
像这样:
- #include <iostream>
- using namespace std;
- struct Point {
- private:
- // 数据成员
- double x;
- double y;
- public:
- // 无参构造函数
- Point(){}
- // 有参构造函数
- Point(double a, double b) {
- x = a;
- y = b;
- }
- // 成员函数: 重新设置数据成员
- void setXY(double a, double b) {
- x = a;
- y = b;
- }
- // 成员函数: 指定格式输出数据成员
- void display() {
- cout <<x << "\t" << y << endl;
- }
};
- int main(int argc, const char * argv[]) {
- // insert code here...
- // 使用构造函数创建结构对象 pointA
- Point pointA(20, 30);
- // 显示 pointA 的数据成员
- pointA.display();
- return 0;
}
模型图是这样的:
它表明: 我定义了一个结构体, 有两个私有的数据成员 x, y, 一个无参构造函数 Point(), 一个有参构造函数 Point(double x, double y), 两个普通的成员函数 setXY(double, x, double y), display();
从结构演变成一个简单的类
使用关键字 class 代替 stuct, 就将一个结构演变成一个标准的类啦! 是不是 So easy!
像这样:
- class Point { // 这里 struct 变成 class, 就完成了从结构到类的演变
- private:
- // 数据成员
- double x;
- double y;
- public:
- // 无参构造函数
- Point(){}
- // 有参构造函数
- Point(double a, double b) {
- x = a;
- y = b;
- }
- // 成员函数: 重新设置数据成员
- void setXY(double a, double b) {
- x = a;
- y = b;
- }
- // 成员函数: 指定格式输出数据成员
- void display() {
- cout << x << "\t" << y << endl;
- }
};
好的, 从现在开始把我们的目光从 struct 移开吧, 让我们聚焦于 class!
面向过程与面向对象
编程语言是我们和计算机交流的桥梁, 编程技术在发展, 同样的编程语言也在发展, 编程语言从最初的 0 和 1, 到汇编语言, 再到面向过程的语言, 再到面向对象的语言, 反应出了我们的编程思想也在不断的进步, 面向过程只是关注解决问题的步骤, 而面向对象关注解决问题的对象, 也就是谁解决这个问题.
下面我用两个经典的例子来诠释面向过程和面向对象的区别
第一个: 五子棋游戏
面向过程是这样的:
(1)开始游戏 -> (2)黑子下棋 -> (3)绘制画面 -> (4)判断输赢 -> (5)白子下棋 -> (6)绘制画面 -> (7)判断输赢 -> (8)返回步骤(2)
面向对象是这样的:
黑白双方, 负责下棋这个操作
棋盘系统, 负责绘制画面
规则系统, 负责判断是否犯规, 输赢等
第二个: 把大象装进冰箱
面向过程是这样的:
(1)把冰箱门打开 -> (2)把大象装进去 -> (3)把冰箱门关上
面向对象是这样的:
冰箱 -> 开门
冰箱 -> 装大象
冰箱 -> 关门
冰箱是一个对象, 它有开门的操作, 装大象的操作, 关门的操作, 大象也是一个对象
总结
面向过程就是关注解决问题的步骤, 像这样: 第一步打开冰箱门, 第二步装大象, 第三步关闭冰箱门
面向对象就是关注解决问题的对象, 像冰箱, 它有开门的方法, 装大象的方法, 关门的方法
大家知道基本的区别和联系就可以啦. 也可以找我细聊哦!
面向对象程序设计的特点
面向对象的程序设计具有抽象, 封装, 继承和多态性的特点
对象
对象是系统描述客观事物的一个实体, 是构成系统的基本单位
对象用对象名, 属性 (数据成员), 操作(功能函数) 三要素来描述
对象名: 用来标识一个具体的对象. 如: zhangsan, lisi 等
属性: 这个对象的数据成员, 也就是特征, 如: 姓名, 年龄, 性别等
操作: 这个对象所具有的行为, 如: 吃饭, 睡觉, 打豆豆等
像这样:
我们有一个对象
对象名: zhangsan
数据成员: 姓名叫张三, 年龄 18 岁
成员函数: 会吃饭, 能睡觉, 还喜欢打豆豆
抽象和类
比如我们还有一个学生对象叫李四
我们现在有两个学生对象一个叫张三, 年龄 18, 一个叫李四, 年龄 20, 比如我们还有一个学生对象叫王五, 年龄 22, 假如我们还有好多个学生.
都有姓名, 年龄的基本属性, 也有吃饭, 睡觉, 打豆豆的行为,
我们把这些对象的共同特征进一步抽象出来, 就形成了类的概念
像这样:
这是一个类,
类名: Student
数据成员: name, age
成员函数: eat(), sleep(), dadoudou()
我们用代码表示是这样的:
- // 定义学生类
- class Student {
- private:
- // 姓名
- string name;
- // 年龄
- int age;
- public:
- // 构造方法
- Student(string aName, int anAge) {
- name = aName;
- age = anAge;
- }
- // 吃饭
- void eat() {
- cout <<name << "吃饭" << endl;
- }
- // 睡觉
- void sleep() {
- cout << name << "睡觉" << endl;
- }
- // 打豆豆
- void dadoudou() {
- cout << name << "打豆豆" << endl;
- }
- };
- int main(int argc, const char * argv[]) {
- // insert code here...
- // 使用构造方法创建学生对象,
- Student zhangsan("张三", 18);
- // 对象方法
- zhangsan.eat();
- zhangsan.sleep();
- zhangsan.dadoudou();
- // 还可以继续创建其它学生对象, 比如李四, 王五, 赵六等
- return 0;
}
类和对象的关系
类相当于模具
对象相当于用模具所制造出来的东西
类是具有相同的属性和操作的一组对象的集合
对象是这些集合当中的一个个体
这样理解:
李四是一个学生 // 正确, 因为李四是对象, 而学生是类
学生就是李四 // 错误, 学生是一个群体, 怎么可能是单个个体呢
封装
一个经典的例子来加深我们的理解吧!
电视机把各种部件都装在机箱里, 遥控器的所有部件也都装在遥控器里, 我们通过遥控器操作电视机, 而不是我们自己摆弄电视机的各个组件! 比如音量 +, 音量 -, 而不是咱们去电视机里摆弄线圈!
封装性就是要求一个对象应该具备明确的功能, 并具有接口以便和其它对象相互作用, 对象内部的数据和代码是受保护的, 外界不能访问它们, 只能对象对外提供的接口可以访问它们. 增加独立, 自己的数据只能由自己来操作.
类的封装是通过定义的存取权限实现的, 分为 private 和 public, 对象的外部只能访问对象的公有部分, 也就是 public 修饰的, 不能访问对象的私有部分, 也就是 private 修饰的.
继承
继承是一个类可以获得另一个类的特性的机制
像这样:
比如我们有 "人" 这个类, 它具有姓名, 年龄这两个属性, 吃饭这个行为
我们又有 "老师" 这个类, 继承自 "人" 类, 所以它有继承过来的 "姓名", "年龄" 属性, 还有自己所独有的 "职工编号" 属性, 有继承过来的 "吃饭" 行为, 还有自己所独有的 "讲课" 行为.
我们又有 "学生" 这个类, 继承自 "人" 类, 所以它有继承过来的 "姓名", "年龄" 属性, 还有自己所独有的 "学号" 属性, 有继承过来的 "吃饭" 行为, 还有自己所独有的 "听课" 行为.
总结
子类只需定义它所特有的特征, 而共享父类的特征
多态性
不同的对象可以调用相同名称的函数, 但可导致完全不同的行为的现象称为多态性.
在 C++ 中, 多态性分为两种, 一种称为编译时多态, 另一种为运行时多态
编译时多态
也就是函数重载. 是指同一个函数名可以对应着多个函数的实现, 具体调用哪个函数由参数个数, 参数类型等来决定
运行时多态
也就是虚函数. 在定义了虚函数后, 可以在基类的派生类中对虚函数重新定义, 以实现所想要的功能
使用类和对象
使用 string 对象
必须包含该类的头文件, #include <string>
像这样:
String str = "RayLee"; // 等价于 String str("RayLee");
在字符串的末尾系统会加上''\0" 字符来表示字符串的结束, 但是在计算字符串长度的时候不包含'\0'
像这样:
String str2 = 'A'; // 错误, str2 是字符串对象, 不能赋值为字符
我们可以把字符串看成是字符数组
所以我们可以这么使用
- // 字符串对象
- string str = "RayLee";
- // 输出字符串中的每个字符, 其中 size()为 string 对象的成员函数, 返回字符串长度
- for (int i = 0; i <str.size(); i++) {
- cout << str[i] << endl;
- }
字符串连接符号 +
作用: 将两个字符串或者字符串与字符拼接起来
像这样:
- // 两个字符串拼接
- string str = "RayLee";
- string str2 = "is a student!";
- string str3 = str + str2;
- cout << str3 << endl;
- // 字符串跟字符拼接
- str3 = str + '!';
- cout << str3 << endl;
- // 现个字符相拼接是不行的
- str3 = 'a' + '?'; // 错误, 这样的话就不是拼接了, 就是加法运算啦
使用 string 类的典型成员函数
- string str = "Hello, World!";
- cout << str << endl;
- // size()函数: 给定字符串的长度
- unsigned long size = str.size();
- cout << "字符串长度:" << size << endl;
- // find(要查找的字符串, 开始查找的起始位置)函数: 要查找的字符串在给定字符串的起始位置
- unsigned long result = str.find("lll");
- if (result>= size) {
- cout << "没有查找到该字符串" << endl;
- } else {
- cout << "字符串起始位置为:" << result << endl;
- }
- // substr(起始位置, 截取长度)函数: 给定字符串的子串
- string subStr = str.substr(2, 8);
- cout << "截取的字符串:" << subStr << endl;
- // getline()函数: 从 cin 对象中读出一行给 string 对象
- string inputStr;
- getline(cin, inputStr, '\n');
- cout << inputStr << endl;
- // swap()交换函数: 将两个 string 对象的内容进行交换
- string str1 = "I am a student!";
- string str2 = "You are a teacher!";
- cout << "交换前:" << str1 << " " << str2 << endl;
- str1.swap(str2);
cout << "交换后:" << str1 << " " << str2 << endl;
面向过程和面向对象不是对立的, 面向对象是建立在面向过程的基础上的, 它们是相互依存的, 面向过程关注于解决问题的步骤, 而面向对象关注于解决问题中出现的对象, 而对象中则封装了解决问题的步骤, 面向对象是更高级的语言, 但它是依赖于面向过程而存在的, 随着计算机科学与技术的发展, 出现更高级的语言也说不定呢?
本系列文章会持续更新! 大家踊跃的留下自己的脚印吧!
来源: https://juejin.im/post/5c306a2551882525a7241987