欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 艺术 > C++—23、C++ 中的继承Inheritance

C++—23、C++ 中的继承Inheritance

2025/2/7 11:36:09 来源:https://blog.csdn.net/Growthofnotes/article/details/145474613  浏览:    关键词:C++—23、C++ 中的继承Inheritance

知识点复习,侵权立删!

一、继承的好处

今天我们一起来讨论C++中的继承,面向对象程序设计中最重要的一个概念。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序更容易。这样做也达到了重用代码功能和提高执行效率的效果。

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类

这就是继承为什么非常有用,因为它可以帮助我们避免写很多重复的代码。代码重复(code duplication)是指我们必须多次地写相同的代码或者代码略微不同但实际上是在做同样的事。为了避免一次次地重复,我们可以把所有通用的功能放在一个父类中,然后很容易地从基类中创建派生类,稍微改变一些功能或者引入全新的功能。继承给我们提供了这样的一种方式:把一系列类的所有通用的代码(功能)放到基类中,这样我们就不用像写模板那样不断重复了。

好了,让我们在代码里看看要怎样做。

二、继承实例

假如我有一个Entity类,然后它将控制游戏里的所有Entity实例。在游戏里有很多非常非常具体的Entity,但是在某些方面它们会共享功能,比如说,可能游戏里每个Entity都有用2个浮点数来表示位置属性,然后,我们可能想给每个Entity移动的能力,也许叫Move方法,参数为xa和ya,用来表示我们想要移动的量。这样我们有了一个叫Entity基类,我们可以说游戏里创建的每个实例都具有这些特性。代码如下:

class Entity
{
public:float X, Y;void Move(float xa,float ya){X += xa;Y += ya;}};

让我们创建一个新类型的Entity,比如说Player,编写我们的Player类,目前为止还没用到继承的

概念,通常如果我们从头开始的话,我们会想要Player也有一个位置属性,因为Player也是一个实体(Entity),让它也有一个位置也是说的通的,我们也想让Player可以移动,因此我们需要一个Move函数,我们最终写的这些和Entity看起来很像。Player类可能会包含一些其他的数据,比如说名字等,把名字加上,你可以说Entity和Player其实是不同的类,Player类如下:

class Player
{
public:float X, Y;const char* Name;void Move(float xa, float ya){X += xa;Y += ya;}
};

你会发现有很多的代码其实就是复制和粘贴的。

这样我们就可以使用继承了。

我们可以扩展Entity类来创建一个新的叫Player的类,而且它还可以存储新的数据,比如说name。另外还要提供额外的功能,比如说基类里不存在的函数PrintName(),现在我们把Player变成Entity的派生类,要这么做:

在类型声明class Player后面写上冒号,然后写上public Entity。如下:

class Player:public Entity
{};

这个Player类不在仅仅只是Player类型,它也是Entity类型,就是说它同时是这两种类型,c++里的类型是个很复杂的话题,因为一方面它们并不是真实存在,另一方面它们又确实很重要,另外一件发生的事情就是player现在拥有了Entity的一切,所有的类成员比如说X和Y,这两个浮点数,同样也包含在Player里,所以我们需要把重复的东西删掉,只保留剩下的东西,如下:

#include<iostream>
class Entity
{
public:float X, Y;void Move(float xa,float ya){X += xa;Y += ya;}};
class Player:public Entity
{
public:const char* Name;void PrintName(){std::cout << Name << std::endl;}
};

这样名字和打印函数保留下来了,现在这个Player看起来很干净了。但是这其实还是Entity,这意味着只看player这个类我们并不能了解全貌,我们必须要往上到Entity类里看看它有什么?因为对于Player来说,在Entity中任何不是私有的(private)成员,Player都可以访问到。我们来尝试下:

假设我在main函数这里创建了一个Player实例,我不但可以调用在player中定义的PrintName函数,我也能调用Move函数,还有可以像这样访问X和Y,就像我在使用一个Entity的实例一样。因为它继承了Entity的所有功能。

另一个我们可以应用的概念叫“多态”,以后我介绍,基本上来说,多态就是使用一个单一的符合来表示多个不同的类型。

你应该记得我之前提到的player不仅仅是Player类型,它还是一个Entity类型。我的意思是我们可以在任何想要用Entity的地方使用Player,这是因为Player拥有Entity的所有内容,甚至更多,当然也不必一定要有更多的内容,它们可以是完全一样的,但是Player总是Entity的一个超集,就是说Player拥有Entity的一切,并且除此之外可以有更多的内容,如果我想创建一个打印Entity对象的独立功能,访问X和Y变量然后把它们打印到控制台上,我可以给这个函数传入一个Player对象,尽管它是接受一个Entity作为参数的,可以这么做的原因是,一个Player类型或者Player类保证会有X和Y变量,它是Entity的派生类,就是说它拥有Entity的所有内容,因为这些多态特征,我们可以做很多很多事情,比如我们可以改变基类的行为,通过重写一个方法给它新的代码来替代父类方法

我们讲的继承是用来拓展现有的类和为基类提供新功能的一种方式,它是面向对象编程的一个最重要的东西。记住,当你创建了一个子类,他会包含父类的一切。另外证明这些的好方法就是,记得我们在Entity中有两个浮点数X和Y,让我们接着把Entity对象的size打印到控制台,可以使用sizeof(Entity),测试如下:

你应该能猜到结果,因为在Entity里我们有两个Float变量X和Y,然后我们接着打印sizeof(Player),它继承了Entity类的所有变量,运行如下:

运行结果为12,在Entity8字节的基础上增加了char*4个字节。

Player确实是继承了Entity的一切,这好像就是我们从Entity里复制了所有东西然后粘贴到Player类里。Player类就是增加了额外功能的Entity。记住这些类的大小和内存实际上是可以变化的,如果我们重写Player里的函数,那么我们就要去维护一个虚函数表,这也需要占用额外的内存。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com