1. 概述
这篇主要讲的是C++类。到这篇,终于来到了面向对象编程,这是一种非常流行的编程方式。面向对象编程实际上只是一种你可以采用的方式来写你的代码。其他语言例如C#、java等主要是面向对象的语言,事实上,你用这些语言,并不能真的写任何其他类型的代码,虽然你也可以尝试,因为这些语言都是面向对象的语言。然而,C++有点不同,因为它并没有强加给你一种特定的风格。用C语言举个例子,C语言实际上并不支持面向对象编程,因为为了面向对象编程,你需要有一些概念,比如类和对象,这些东西C语言没有。然而,如果你想使用面向对象的话,C++会添加所有这些功能,在某种程度上,使用面向对象是一个好主意。我们将在这篇中讨论什么是类。
简单来说,类只是对数据和功能组合在一起的一种方法。例如一款游戏。在游戏中,我们可能想要一些代表角色的东西,那么我们需要什么样的东西来代表一个角色呢?我们当然需要一些数据,例如,角色在游戏中的位置,角色可能拥有的某些属性,例如,角色移动的速度,我们还可能需要一些3D模型,代表角色的屏幕形象。所有这些数据都需要存储在某个地方,我们可以为所有这些创建变量。
下面来看看这个游戏的案例
2. 案例
1. 项目准备
一个简单的项目,项目中有一个main.cpp文件,文件内容如下
2. 开始案例
假设我们想要创建一个角色。在代码上,我们可能想要一个角色位置,假设是平面位置,我用x,y表示,所以声明int x, y;
。然后角色移动会有一个速度,用speed表示,假设速度为2,声明int speet = 2;
,如下
现在咱们声明的变量x,y,speed都是整数,我们发现,这有点乱,因为这些名字都太普通了。对于变量x,y,我们可能想写成PlayerX,PlayerY,对于speed,我们可能想写成PlayerSpeed。如下
但是这看上去还是有点乱,特别是当我们游戏有2个角色时。然后我们不得不复制一份代码,然后命名上改为PlayerX0,PlayerX1等,如下。
当然,我们可以使用数组,但重点还是一样的,它们只是一堆没有组合在一起的变量,它们是无组织的。它们只是被放在我们的代码中,这不是一个好的主意。
使用另一个很好的例子可以说明为什么这么烦人。如果我们想写一个函数来移动角色或者改变属性类似的东西。比如写个Move函数,我们需要将角色的三个参数指定为整数参数,如void Move(int x, int y, int speed);
。
所有这一切都变成了如此多的代码,难以维护,非常混乱。所以我们要做的是简化它,通过使用类。我们可以创建一个叫做Player的类,然后它包含了角色的所有数据,我们想要所有这些变量,变成一种类型。所以,接下来,我们创建一个名为Player的类。
3. 创建类 class
我们通过使用关键字class
,然后给它一个名字来实现,如,class Player
。这个名字必须是唯一的,因为class
是类型,这里是创建一个新的变量类型。然后就是接左右大括号{}
,如下
注意,我们在类大括号结束的位置要加上一个分号;
。然后,在类的大括号里面,我们可以指定角色的所有变量
OK,我们创建了一个全新的类叫Player,本质上它是一种类型。
4. 创建类对象
如果我们开始用Player类,我们可以把它当做变量来创建。我们写的类型是Player
,然后我们给它起一个名字,假设为player,就像这样,Player player;
。
我们给一个新变量命名为player,这个新变量的类型是Player
。当然这种类型的定义在class Player
这里
由类
类型构成的变量称为对象,新的对象变量称为实例。我们现在要做的是Player player;
实例化一个Player
对象,因为我们已经为那个Player
类型创建了一个新实例player。如果我们想设置角色的变量。可以通过对象后接点的方式,如player.x
,然后给角色变量赋值,如player.x = 5;
。
我们尝试单文件编译此文件 ctrl + F7
可以看到,我们得到了一个错误。错误信息"Player::x": 无法访问 private 成员(在"Player"类中声明)
告诉我们player不能访问在类Player中声明的已有成员。这是因为可见性
的原因。
5. 类成员可见性
当我们创建一个新类时,我们可以选择指定类中的内容的可见性。默认情况下,一个类中所有的东西都是私有的。这意味着只有类中的函数才能访问这些变量。然而,我们现在希望能够在main函数中访问这些变量,我们需要做的是,将类中的变量设置为共有,通过public
关键字。
public
意味着我们可以在类之外的任何地方访问这些变量。
现在我们单文件编译此文件ctrl + F7
可以看到编译通过了。
现在,我们实现了第一个目标,已经彻底清理了代码,把所有的变量都放在了一个地方,这些变量集合可以代表一个player,所以我们把它们很好的分组了。现在我们有了这些数据,假设我们想让player做一些事情,例如移动,所以我们要写一个函数来改变变量x和变量y的值。那么我们应该怎么做呢?
我们可以把它写成单独的函数void Move
,然后我们需要给函数Move一个我们想要移动的Player,我们需要通过引用传递Player& player
,因为我们要修改Player对象,然后我们还要接收,一个X轴向的移动距离xa,一个Y轴向的移动距离ya,然后,我们在Move函数体内要做的是改变player对象的x,和y,player.x += xa;
player.y += ya;
,当然,我们也可以乘上speed,player.x += xa * player.speed;
player.y += ya * player.speed;
,如下。
接下来,我们在main函数中调用这个Move函数,假设x移动1,y移动-1
6. 类方法
我们已经写了一个可以移动player的函数。然后,我们可以做的更好一点,上面有说过,类实际上可以包含函数,这意味着我们可以将move函数移动到类中。类中的函数被称为方法
。
我们可以把Move函数移动到Player
类里面
好了,现在,move函数在Player
类里面了,所以我们可以直接得到Player类的这些变量。也就是Move函数不需要传入Player& player
引用了,因为move函数已经在Player
类里面了。
然后move中所有这些x,y和speed,指的是当前对象的变量。
所以在mian函数中调用,也需要改动
现在,我们已经简化了我们的代码。每个Player对象都有自己的move函数,当我们为指定的Player对象调用move时,这个指定的Player对象将会移动。这与在Player类之外的move函数没有什么不同,在功能上。只是将move函数移动到Player类里面,这样可以使我们的代码更干净,当我们处理很多代码时,这是一个巨大的优势。因为我们有越多的代码,情况就越复杂,就越需要有这样的代码,来保持代码整洁,这是非常重要的。
以上就是类的基本概念。类允许我们将变量分组到一个类型中,并为这些变量添加功能。
我们再看下代码,我们真正做的是在一个类类型中,定义了三个变量,还有一个处理这些变量的函数,这就是我们所做的,当然,这个函数可以做任何事,但它的要点,我们有数据和处理这些数据的函数,这就是所谓的类了。
类有很多用途,后续的文章会继续深入。本篇讨论的是类的基本概念。我们可以用类做很多事情,同时,虽然类非常有用,可以让我们的代码非常简洁,但如果不使用类搞不定的事情,用类也一样搞不定。类不会添加任何新功能,我们可以用类搞定的事情,不用类一样可以搞定,这就是为什么像C这样的语言存在并且是完全可用的原因。C语言没有所谓的类,然而我们依然可以编写类,使我们的生活更容易。因为类本质上只是语法糖,我们可以使用它来组织我们的代码,使代码更容易维护。