文章目录

  • 7.面向对象—基础篇
    • (1). 飞船和子弹的生成和保存
    • (2). 飞船和子弹的碰撞检测
    • (3). 类与对象的基本特征
      • #1.属性与方法
      • #2.面向对象的三大基本特征
      • #3.封装
      • #4.继承
      • #5.多态
    • (4). 类的基本构成
      • #1.按属性与方法区分
      • #2.按成员的所属区分
      • #3.按成员可否在类外访问区分
    • (5). C++的面向对象与其他语言的区别
    • 小结

7.面向对象—基础篇

  从这一章起,我们就会开始介绍面向对象(Object Oriented) 的程序设计模式,面向对象的程序设计模式在一系列问题的解决过程中可以发挥很大的作用,我们来看这么一个例子。

(1). 飞船和子弹的生成和保存

  假设我们需要设计一个游戏,有这样一个需求:玩家驾驶飞船,飞船需要发射子弹,子弹可以有成百上千个。那假设我们用一个double数组存储子弹,那我们可能需要编写这么一串代码:

#include <iostream>
using namespace std;void add_bullet(double x, double y, double z, double bullets[][3], size_t index)
{bullets[index][0] = x;bullets[index][1] = y;bullets[index][2] = z;
}void show_bullet(double bullets[][3], size_t cnt)
{for (int i = 0; i < cnt; i++) {cout << "(" << bullets[i][0] << ", " << bullets[i][1] << ", " << bullets[i][2] << ")" << endl;}
}int main()
{double bullets[100][3]{ {0.0, 0.0, 0.0} };add_bullet(1.0, 2.0, 3.0, bullets, 1);show_bullet(bullets, 2);return 0;
}

  那我们要存一个子弹进去,还要在函数里把这个数组传入,还要传入一个index进去,看上去非常的不优雅啊,不过这还只是记录,在游戏的运行过程中,我们还需要检测飞船是否和子弹发生了碰撞,从而对飞船进行扣血等操作。

(2). 飞船和子弹的碰撞检测

为了完成扣血等等操作,我们需要判定子弹是否击中了飞船,由于飞船的模型是不规则的,我们可以简化一下,就判定子弹是否出现在以飞船中心为圆心,2.0为半径的圆内,如果是的话就判定为发生碰撞,这当然不算太精准,未来你可以构造一个更加精确的图形用来进行碰撞检测,不过现在就用我说的这个精简模型就好了,很简单:

#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;void add_bullet(double x, double y, double z, double bullets[][3], size_t index)
{bullets[index][0] = x;bullets[index][1] = y;bullets[index][2] = z;
}void show_bullet(double bullets[][3], size_t cnt)
{for (int i = 0; i < cnt; i++) {cout << "(" << bullets[i][0] << ", " << bullets[i][1] << ", " << bullets[i][2] << ")" << endl;}
}bool check_collision(double bullet_x, double bullet_y, double bullet_z, double ship_x, double ship_y, double ship_z)
{if (sqrt(pow((bullet_x - ship_x), 2)+ pow((bullet_y - ship_y), 2)+ pow((bullet_z - ship_z), 2)) < 2.0){return true;}else return false;
}int count_collision(double bullets[][3], size_t size,double ship_x, double ship_y, double ship_z)
{int ans{ 0 };for (int i = 0; i < size; i++) {if (check_collision(bullets[i][0], bullets[i][1], bullets[i][2], ship_x, ship_y, ship_z)) {ans++;}}return ans;
}int main()
{double bullets[100][3]{ {3.0, 3.0, 3.0} };for (int i = 1; i < 100; i++) {add_bullet(static_cast<double>(rand() % 10),static_cast<double>(rand() % 10), static_cast<double>(rand() % 10), bullets, i);}show_bullet(bullets, 10);cout << count_collision(bullets, 100, 1.0, 2.0, 3.0);return 0;
}

“很简单”,那个碰撞的bullet_x之类的坐标值你可以写成两个数组的形式,但这还是很奇怪,我们为什么不能自己定义一个叫做子弹的数据类型出来呢?这样操作的话,我们或许可以把代码简化成这样:

bool check_collision(Bullet bullet, Ship ship); // 定义暂时不给出
int count_collision(Bullet bullets[], size_t size, Ship ship)
{int ans{0};for (size_t i = 0; i < size; i++) {if(check_collision(bullets[i], ship)) {ans++;}}return 0;
}

  这简洁太多了,而且你发现,代码相比于用数组更加接近于自然语言,我们很容易知道检测的是子弹和飞船的碰撞,而不是三个浮点数和另外三个浮点数的“碰撞”,这边是面向对象程序设计模式的一个优势——定义我们所需要的数据类型,写出更加易读的代码。

  而这样我们定义的Bullet和Ship就是类,这样的设计模式就叫做面向对象的程序设计模式。

(3). 类与对象的基本特征

#1.属性与方法

  我们使用类(Class)完成对于一类事物的抽象,一个类应当有其对应的属性与方法,例如飞船与子弹的例子,飞船有位置、速度、血量三大属性,具有位置变换、加减速、发射子弹三个方法,而我们在实现面向对象的程序设计的过程当中主要也是在设计类的属性与方法。

#2.面向对象的三大基本特征

  面向对象有三大基本特征:封装、继承和多态

#3.封装

封装是指将类的属性与方法捆绑,同时可以设定属性与方法的所有权。举个例子,我们上面所定义了飞船类,我们可以把三大属性和三个方法全部打包成一个数据类型,这样很明显地提高了代码的可读性,之后还可以根据需要重载运算符,以制造出更加符合我们要求的类。

#4.继承

继承是指一个类可以由另一个类派生而来,例如我们上述说的飞船与子弹具备位置、速度等的共同特征,有的时候我们可以不需要针对于每个类都重新设计这一部分特征,继承是基于抽象的更深层次的抽象(抽象可以简单理解为提取一个具象化物体的属性和操作,从而用提取出的属性和操作代表同类所有具象化物体的过程),也就是说,我们提取出了飞船和子弹的位置、速度等共同特征,形成了一个更抽象的基类,我们给它起个名字叫做SpaceObj,那么子弹和飞船就可以由SpaceObj类派生而来。

#5.多态

多态则是相同的操作或函数处理不同类别的对象可以获得不同的结果,例如:对于整数a和整数b,a+b的操作就是简单的相加,而对于复数a和复数b,a+b的操作则是实部和虚部分别相加,同样是operator+(加法操作),他们的处理方式和结果不同,这就是多态。

(4). 类的基本构成

#1.按属性与方法区分

  类的基本构成可以分为属性与方法,属性即为对象所具备的一些值,它可以被改变,例如人的身高、体重会发生变化,这些就属于属性。而人可以吃饭,睡觉,这都是一些操作,这些操作可能会对属性造成改变,可能不会,这样的一系列操作就叫做方法,方法和函数其实是一个单词(function),我们说的方法其实也就是类内的函数罢了。

#2.按成员的所属区分

  类的成员就是类中的所有属性与方法的统称,可以依照所属分为类成员对象成员,类成员属于类,而对象成员属于成员。我们来举个例子,例如人口这个属性应当是只属于人类这个范畴的,对于任何一个人(每一个人都是人类的实例),都不存在人口这个属性。因此这部分属于类,而不是任何对象的成员就称为类成员。对象成员就是只属于对象了,例如人类没有身高,但是每个人都具有身高的属性。
  既然都已经叫做类成员了,那方法和属性当然都可以是类的成员了。假设我们要声明一个类成员,我们需要在其前面加上static关键字。例如:

class People
{static int population; // 类变量,人口
public:double height; // 成员变量,身高double weight; // 成员变量,体重static void evolve(void); // 类方法,进化
};

  就是这样,具体的设计方法我们之后再来说

#3.按成员可否在类外访问区分

  按照成员是否可在类外访问,我们将成员分为私有、公有以及受保护三个类别,对应在C++中用private、public和protected三个关键字表示。
  和C语言的struct一样,我们可以通过点运算符访问类内的成员,例如:

class Person
{public:double height;double weight;void set_height(double height){this->height = height;}
};
Person p;
p.height = 180;
p.weight = 70;

  假设我们想知道这个对象p的身高,我们就可以用p.height来访问。同理,p.weight可以访问其身高,这就是公共成员,它可以被任意地在类定义外进行修改与访问。

  不过如此自由可能会产生一些麻烦,你可能一不小心就通过p.height = 190;改掉了对象p的身高,这好像不是一件好事,为了保障一部分属性和方法只能从类内访问,我们需要使用private关键字来标记私有的属性:

class Person
{private:double height;double weight;
public:void set_height(double height){this->height = height;}
};

  这样一来,如果你再去试图直接使用p.height了解p的身高,就会报错了,因为p的身高是私有的,你不能直接通过点运算符访问对象的私有属性
  C++的class关键字中假设没有加上private标签就直接写成员,这一部分成员默认为private,因此上述代码和下面的是等价的:

class Person
{double height;double weight;
public:void set_height(double height){this->height = height;}
};

  这样写也无可厚非,我是更推崇前者的,因为私有成员和共有成员看起来更加一目了然。

  再来设想下面一个例子,你是从你妈那儿衍生来的(好怪的说法),很多属性是直接继承来的,例如长相还有一些其他的遗传特性,但是也有一些是家长私有,而你不具备的,例如家长的钱包归家长自己所有,而不会继承给你(不要细究,至少现在是不会继承给你的),我们把它放入C++中,这就变成了这样一个问题:由基类衍生出的子类,是可以继承基类的一部分成员的,但是要继承哪一部分呢?
  首先是将公有成员继承,这很好理解,外面都可以随意访问的成员,也当然应该继承到子类中。那么私有成员呢?很明显,私有就应该是比较强的特征,某个人私有的东西不应该随意继承下去,例如家长的钱包不会在你一出生就继承给你。因此,私有成员在子类和外部都是不可直接访问的
  那这就有点点问题了,一个家庭里总有点什么秘密,只有家里人知道,比如保险箱的位置,这一部分的属性可以继承给子类,但是又不想让外部访问的,怎么解决呢?这时候就要用到受保护成员了,关键字为protected的成员可以保证这样一件事情:由某个类继承的受保护属性可以由子类访问,但不能从外部访问,这样就解决了!成员的各种关系就很清晰了。
  不过继承这方面还有一些其他的问题,例如公有继承、私有继承和受保护继承这三种不同的继承方式,这等我们后续细讲类的继承的时候再来说说。

(5). C++的面向对象与其他语言的区别

  C++不是一门纯粹的面向对象的语言,因为本身是从C语言发展而来,要全面支持C语言的语法就不能随便抛弃C的语法习惯。
  Java和Python3中的所有类都是默认基于一个程序设定的基类的,也就是说:Java和Python3中的一切都是对象,所有的类也都是基于程序最底层的一个基类的,这样的操作使得Java和Python整个语言都是建立在面向对象之上的。
  这也没什么不好的,但是这样的改造方式并不适合C++,我们首先要明确,基本上所有的C语言代码在C++上都是合法的,那么假设说我们在C++中设定一个语言底层的基类,那就会影响C代码在C++上的正常运行,因为C代码中的程序设计并不遵照面向对象的模式,因此,C++的类不会默认继承基类

  二来是继承,Java在面向对象范式上的造诣是非常深的,我们看看下面的代码:

// Filename: Main.java
public class Main {public static void main(String[] args) {System.out.println("Hello, world!");}
}

  这是使用Java打印Hello, world!的示例代码,我们可以看到这个文件的第二行就是一个叫做Main的类的定义,内部需要定义一个main函数作为入口,而这个main函数也是Main类的公有成员,并且是类成员(static关键字),之后是void类型(无返回值) 之后再完成一系列的操作。
  Java的整个程序架构就是建立在一个又一个类之上的,用Java你不可能避开面向对象的程序设计模式。而C++可以,我们可以完全使用C的模式进行设计。
  Java在继承方面比较谨慎,采取了单继承的特性,即:一个类只能由最多一个类派生而来,而C++支持多继承,即:一个类可以由任意多个类派生而来,多继承的方法是有一些问题的,过多的使用多继承可能会导致程序的结构比较混乱,假设你一个类从七八个类继承而来,你由为什么不尝试把他们写成一个类呢?又或者是你为什么不尝试把这七八个类也变成单继承的模式一个一个继承下来呢?

  最后要提的是私有性,我们知道python的私有属性是伪私有,例如:

class A:def __init__(self, a):self.__a = a; # 定义了一个私有属性a(两个下划线)
a = A(3)

  这时候我们如果直接通过a.__a或者a.a访问a都是不可行的,但假设你把访问的属性改成a._A__a,那就行了,这,这就是假的私有啊,只是把属性名字改了,在私有属性名前加了一个"_类名"而已。

  C++实际上也有这种操作,不过这种操作的选择权在于自己,C++中引入了friend关键字,中文称之为友元,设计之初大家认为,人有的时候会对自己的朋友开放一些私有的属性,因此我们可以通过friend关键字,在某些类中为别的类添加一些方法,并且使用了friend关键字的函数可以直接访问对应类中的私有成员,不过这个就需要等到之后我们再来说了。

小结

  这一篇中我们介绍了面向对象的一些基础知识,还介绍了C++的面向对象和别的语言的一些区别,下一篇中我们会开始正式进入面向对象的程序设计,所以我们会首先介绍类的构造函数。

面向对象和C++基础—面向对象(基础篇)相关推荐

  1. Java基础-面向对象第二特征之继承(Inheritance)

    Java基础-面向对象第二特征之继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承的概述 在现实生活中,继承一般指的是子女继承父辈的财产.在程序 ...

  2. (20)Java基础 --面向对象(1)

    目录 面向对象 一.概述 二.生活举例 三.类与对象的关系 四.类的构成 五.类的定义 类的属性 类的方法 创建实例(对象) 内存分配图 六.对象的基本使用 七.局部变量与成员变量的区别 八.面向对象 ...

  3. Java 基础 - 面向对象(不错N多教程集合)

    著作权归https://pdai.tech所有. 链接:Java 基础 - 面向对象 | Java 全栈知识体系 本文主要介绍Java OOP 面向对象基础和相关类图.@pdai Java 基础 - ...

  4. java 向父类_Java基础——面向对象(Object父类)

    原标题:Java基础--面向对象(Object父类) 声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权:凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记. Obj ...

  5. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  6. polymorphism java_Java基础-面向对象第三大特性之多态(polymorphism)

    Java基础-面向对象第三大特性之多态(polymorphism) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多态概述 多态是继封装,继承之后,面向对象的第三大特性,多态的 ...

  7. python基础程序设计与面向对象程序设计_python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  8. 基于Java基础-面向对象实现植物大战僵尸简易版

    基于Java基础-面向对象实现植物大战僵尸简易版 前言 游戏设计 游戏对象 游戏内容 游戏优化 放置植物的优化 移除植物的优化 游戏可玩性的优化 添加游戏背景音乐 后续优化 源码分享 前言 从零开始学 ...

  9. Python面向对象之二:面向对象基础

    Python面向对象之二:面向对象基础 一.面向对象介绍 通过一个例子引入对面向对象思想的理解: 假设自己是如来佛祖,想找四个人去西天取经,于是便找了四个人,但是这四个人没有明显的长相特点,于是就给一 ...

  10. python基础—面向对象

    python基础-面向对象 面向对象 面向过程VS面向对象 类和实例 实例变量和类变量 类的方法 实例方法 静态方法 类方法 面向对象的组合用法 封装.继承和多态 封装 继承 派生 方法的重写 继承注 ...

最新文章

  1. maven根据profile动态选择配置文件
  2. 【响应式Web前端设计】CSS3伪类与伪元素的区别
  3. Sed教程(一):简介、环境设置、工作流程
  4. 对于计算机网络的整体框架的概括(转载)
  5. 编译安装PHP-7.2.8
  6. Tensorflow深度学习应用(筑基篇)
  7. 京东智联云张晓东cdn_京东智联云:数智力量驱动实体经济复苏
  8. Atitit 建立新组织集团模型的框架基本制度与一些原则
  9. 佳能g3800故障灯说明书_虎林2020定制FW6117移动工作灯
  10. redfish、ipmi返回状态码
  11. 数据库和SQL基本知识点
  12. 【linux】rpm和src.rpm、rpm和noarch.rpm的区别
  13. 解决iPhone发送短信显示红色感叹号:尚未送达
  14. html怎么解压缩文件,压缩包7z如何解压
  15. macOS SwiftUI 进度指示器组件规范之 01 进度指标是什么 Progress Indicators
  16. win10浏览器加载很慢_Win10系统打开网页速度很慢的解决办法
  17. Flutter 底部跟随键盘并且页面跟随键盘
  18. 纯前端语言编写音乐播放器
  19. Git连接GitHub仓库,同步上传图片及CSDN外链图片转存失败解决方案
  20. Graphhopper OSM地图路径规划导航 离线搭建教程

热门文章

  1. C语言-学生管理系统源代码
  2. 用Python做股市数据分析(一)
  3. html乱码解决方法
  4. USB转串口芯片CH9101U
  5. maven项目依赖导入不进去的解决方法或者报错的情况
  6. mysql非主键索引_主键索引和非主键索引解析
  7. php算前端还是后端,php属于后端还是前端
  8. USB Audio设计与实现
  9. 机器学习第1集——分类决策树tree.DecisionTreeClassifier()
  10. 很热闹的帖子:透露公关内幕 网络媒体编辑教您如何索取公关公司好处费