【C++ 概念区分】C++ 中覆盖,重写,隐藏 三者的区别


角度/特性 覆盖(Overriding) 重载(Overloading) 隐藏(Hiding)
定义 子类中的函数与父类中的函数具有相同的函数名和参数列表,但可能有不同的实现。 同一个类中的函数具有相同的函数名,但参数列表不同。 子类中的函数与父类中的函数具有相同的函数名,但参数列表可能不同。
作用 改变父类中的函数的行为。 提供多种方式来执行相同的任务。 阻止父类中的函数在子类中的访问。
调用 通过父类的引用或指针调用子类对象时,会调用子类的函数。 根据传递的参数类型和数量,编译器决定调用哪个函数。 通过子类的引用或指针调用时,只能访问子类的函数。
多态性 支持多态性。 不支持多态性。 不支持多态性。
使用场景 当子类需要改变父类的行为时使用。 当需要执行相同的任务,但输入参数类型或数量不同时使用。 当子类需要阻止父类函数的访问时使用。

重载overload

在C++编程中,重载(overload)是一种强大的功能,它允许在同一可访问区内声明几个具有不同参数列表的同名函数。程序会根据不同的参数列表来确定具体调用哪个函数,这种机制就是重载。

重载的特征包括:

  1. 函数必须处在相同的空间中,即相同的范围内。

  2. 函数名必须相同。

  3. 参数必须不同,即参数个数不同,或相同位置的参数类型不同。

  4. const成员函数可以和非const成员函数形成重载。

  5. virtual关键字、返回类型对是否构成重载无任何影响。

需要注意的是,重载不关心函数的返回值类型,即返回类型不同无法构成重载。这是因为在调用函数时,编译器并不知道函数返回值将被如何使用,因此无法根据返回类型来选择合适的重载版本。

此外,C++中的const成员函数也可以构成overload。这是因为const成员函数和非const成员函数在对象的const性上有所不同,因此它们可以被视为两个不同的函数。

总的来说,重载是C++中的一种重要特性,它提供了代码的灵活性和可读性,使得函数可以根据不同的参数类型和数量进行不同的操作。

覆盖override

覆盖(Override)是面向对象编程中的一个重要概念。它指的是在派生类(子类)中重新定义父类中的函数。覆盖的函数,其函数名、参数列表、返回值类型必须与父类中被覆盖的函数完全一致。覆盖函数和被覆盖函数的主要区别在于函数体,也就是花括号中的部分。当派生类对象调用这个同名函数时,系统会自动调用派生类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就被称为覆盖。

覆盖的特征包括:

  1. 不同的范围:覆盖函数位于派生类,被覆盖函数位于基类。

  2. 函数名字相同:覆盖函数和被覆盖函数的名称必须完全一致。

  3. 参数相同:覆盖函数和被覆盖函数的参数列表必须完全一致。

  4. 基类函数必须有virtual关键字:只有被声明为virtual的基类函数才能被派生类覆盖。

覆盖的主要目的是为了让派生类可以改变和扩展基类的行为。通过覆盖,派生类可以提供与基类函数相同的接口,但具有不同的实现,这样可以增加代码的灵活性和可重用性。同时,覆盖也是多态性的一个重要体现,使得我们可以通过基类的指针或引用来调用派生类的函数,从而实现动态绑定。

隐藏hide

所谓的"隐藏",在面向对象编程中,特指当派生类类型的对象、指针、引用访问基类和派生类都有的同名函数时,访问的是派生类的函数,这就相当于隐藏了基类的同名函数。这种隐藏规则的底层原因其实是C++的名字解析过程。在继承机制下,派生类的类域被嵌套在基类的类域中。派生类的名字解析过程如下:

  1. 首先在派生类类域中查找该名字。
  2. 如果第一步中没有成功查找到该名字,即在派生类的类域中无法对该名字进行解析,则编译器在外围基类类域对查找该名字的定义。

隐藏的特征主要有两个:

  1. 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏。这是因为在C++中,函数的参数列表是函数签名的一部分,如果参数列表不同,那么这两个函数就被视为完全不同的函数。这种情况下,派生类的函数并不是重载基类的函数,而是隐藏了基类的函数。

  2. 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏。这是因为在C++中,只有当基类的函数被声明为virtual时,派生类的同名函数才会覆盖基类的函数,否则,派生类的函数会隐藏基类的函数。

总的来说,函数的隐藏是C++中一个重要的概念,理解这个概念对于理解C++的继承和多态机制有着重要的作用。

编译器的处理过程

在C++中,覆盖(Overriding)、重载(Overloading)和隐藏(Hiding)是三种不同的概念,它们在编译器处理上有着不同的机制。

  1. 覆盖(Overriding):覆盖发生在继承关系中,当派生类中的函数和基类中的虚函数有相同的函数名和参数列表时,我们说派生类的函数覆盖了基类的函数。在编译器处理覆盖时,会在虚函数表(vtable)中为派生类的函数分配一个新的入口,这样在运行时,通过基类指针或引用调用该函数时,会根据虚函数表找到派生类的函数,实现动态绑定。

  2. 重载(Overloading):重载是指在同一作用域中,有多个同名函数,但参数列表不同。编译器处理重载时,会根据函数调用时提供的参数类型和数量,选择最匹配的函数进行调用。这个过程在编译时完成,称为静态绑定。

  3. 隐藏(Hiding):隐藏发生在继承关系中,当派生类中的函数和基类中的函数有相同的函数名,但参数列表不同,或者函数名和参数列表相同但基类函数不是虚函数时,我们说派生类的函数隐藏了基类的函数。在编译器处理隐藏时,会优先在派生类的作用域中查找函数,如果找到了就调用派生类的函数,否则就在基类的作用域中查找。这个过程也是在编译时完成,称为静态绑定。

总的来说,覆盖涉及到运行时的动态绑定,而重载和隐藏涉及到编译时的静态绑定。这三种机制都是C++中多态性的重要组成部分。

结语

在我们的编程学习之旅中,理解是我们迈向更高层次的重要一步。然而,掌握新技能、新理念,始终需要时间和坚持。从心理学的角度看,学习往往伴随着不断的试错和调整,这就像是我们的大脑在逐渐优化其解决问题的“算法”。

这就是为什么当我们遇到错误,我们应该将其视为学习和进步的机会,而不仅仅是困扰。通过理解和解决这些问题,我们不仅可以修复当前的代码,更可以提升我们的编程能力,防止在未来的项目中犯相同的错误。

我鼓励大家积极参与进来,不断提升自己的编程技术。无论你是初学者还是有经验的开发者,我希望我的博客能对你的学习之路有所帮助。如果你觉得这篇文章有用,不妨点击收藏,或者留下你的评论分享你的见解和经验,也欢迎你对我博客的内容提出建议和问题。每一次的点赞、评论、分享和关注都是对我的最大支持,也是对我持续分享和创作的动力。


阅读我的CSDN主页,解锁更多精彩内容:泡沫的CSDN主页
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_21438461/article/details/131617068