对于C++中多态性是面向对象中很重要的特性之一,每种面向对象的语言对于多态的实现都不尽相同。
最近,学习中发现一段既陌生又熟悉的代码,大致情况如下#include
#include <iostream>
using namespace std;
class BaseClass
{
public:
virtual void Display()
{
cout<<"BaseClass::Display()"<<endl;
}
virtual void Display(int a)
{
cout<<"BaseClass::Display(int a)"<<endl;
}
};
class ExtendClass:public BaseClass
{
public:
virtual void Display()
{
cout<<"ExtendClass::Display()"<<endl;
}
virtual void Display(int a)
{
cout<<"ExtendClass::Display(int a)"<<endl;
}
virtual void Display(float a)
{
cout<<"ExtendClass::Display(float)"<<endl;
}
};
int main()
{
BaseClass* ptrBaseClass = new BaseClass();
ptrBaseClass->Display();
ptrBaseClass->Display(1);
ptrBaseClass->Display(1.1);
return 0;
}
代码的核心思想是
1.基类实现了多个虚函数
2.子类继承基类并且override所有虚函数
3.作者发现子类应该“重载一下”以满足需求,这样的需求原因可能很多
代码即熟悉是因为,overload(重载)的需求在实际应用中很多,因此不感到奇怪。
陌生的原因是,这种写法感觉很奇怪,没见过(因为是错误的,所以没人这么写)
输出结果为
BaseClass::Display()
BaseClass::Display(int a)
BaseClass::Display(int a)
并且在编译是编译器发出强制将float转换为int的警告
首先效果肯定不是原有作者要的结果,然后我开始分析原因
根据Thinking in C++中对于vptr和vtable的解释,貌似我无法找到与这种现象有关的详细解释,也许是我没有发现。
随后我便开始自己解释:
既然所有的虚函数都存放在vtable中,那么指针通过vptr查找到vtable中虚函数时,应该也能找到“float”版的函数。但是他为什么就会去调用int版本呢?通过以往经验我查看了反汇编
发现调用int和调用float部分的汇编代码一模一样,我开始认为这一切的原因出在了编译过程中。可是我始终无法从vptr和vtable的角度出发进行解释这种现象。
最后在请教了高人之后,知道了一件很重要但始终被我误解的事(都是以前教条主义惹得祸,当时学的时候就应该追根溯源)。
当诸如ptrBaseClass->Display();话出现时,编译器是如何解释的呢?
1.因为指针是基类的,因此他将查看基类的所有函数,查看是否满足要求的。
2.如果查看到且查看到的函数发现是virtual的,则在翻译成汇编时翻译成:请到vtable中偏移地址为XXX的地方寻找代码。
3.如果不是virtual,则直接把基类的代码地址获得
4.如果没有在基类的函数中查找到相同的函数,则报出找不到的错误
发现没有,其实多态在C++中的实现还是根据基类的指针来查看函数是否合法。
做个实验,如果你在子类中新增一个函数,然后通过基类进行调用,发现该函数不存在,编译错误。
因此在编译时,函数具体代码区的查找是根据基类指针来的。
当遇到多态时,无非就是告诉调用者,请到具体对象实例中vptr所指向的vtable中所指向的地址去寻找代码,这个过程是运行时完成的。
综上所述,对于我个人而言更加明确了一点,不要在多态的时候去想重载,这是不可能的。
分享到:
相关推荐
《C++多态技术的实现和反思...理解C++多态的内部机制和局限性,有助于程序员做出更合理的设计决策,避免陷入性能瓶颈和设计陷阱。通过精心设计和策略应用,C++的多态特性仍能为构建高效、灵活的软件系统提供强大支持。
虚函数是C++中实现动态多态的基础。通过在基类中声明虚函数,子类可以重写这些函数,使得在使用基类指针或引用调用该函数时,实际执行的是子类的版本。这被称为动态绑定或晚期绑定,与静态绑定(早期绑定)相对。...
虚函数是C++中实现动态多态的关键。在基类中声明虚函数,可以让子类覆盖这个函数并提供自己的实现。这样,我们就可以通过基类指针或引用调用子类的特定版本,即使在编译时不知道实际的对象类型。例如: ```cpp ...
本文将通过两个具体的代码实例,帮助你深入理解和掌握多态和虚函数的用法。 首先,我们需要理解多态的基本定义。多态是指一个接口可以有多种不同的表现形式或行为。在面向对象编程中,多态分为静态多态(编译时多态...
内容概要:文章详细讲解了面向对象编程的关键概念——多态,并提供了详细的示例和实现代码。主要内容包括多态的定义...其他说明:文中不仅有理论解说还有丰富的例子代码,帮助读者深入理解和掌握多态的本质和使用技巧。
在面试过程中C++的多态实现机制经常会被面试官问道。大家清楚多态到底该如何实现吗?下面小编抽空给大家介绍下多态的实现机制。 1. 用virtual关键字申明的函数叫做虚函数,虚函数肯定是类的成员函数。 2. 存在虚...
首先,理解C++中的多态性。在C++中,多态主要通过虚函数(Virtual Functions)和抽象类(Abstract Classes)来实现。虚函数允许子类重写基类的方法,使得调用对象方法时,实际执行的是子类的版本。抽象类则定义了一...
这个“经典C/C++多态实例”可能包含一系列的示例,展示了如何在C/C++中实现和利用多态性。下面我们将详细探讨多态性的概念、实现方式以及其在实际编程中的应用。 多态性(Polymorphism)一词源自希腊语,意为“多种...
虚函数表(vtable)是实现这一功能的关键,理解vtable的工作原理有助于深入理解C++的动态绑定。 7. **模板与泛型编程**:C++模板允许我们编写泛型代码,以适应不同类型的数据。理解模板的实例化、类型推断和模板元...
1. **虚函数**:虚函数是C++中实现多态的关键。在基类中声明一个虚函数,意味着所有派生类都可以覆盖这个函数,从而实现不同的行为。虚函数声明使用关键字`virtual`,如: ```cpp class Base { public: virtual ...
今天我们将深入探讨C++中的多态性,包括虚函数、纯虚函数、抽象类以及动态绑定等概念。 首先,**虚函数(Virtual Functions)** 是实现多态性的重要机制。当在一个基类指针或引用上调用虚函数时,C++会根据实际指向...
在这个“类的多态练习”中,我们将深入探讨这一关键概念。 首先,我们要明白多态性的两种主要形式:静态多态(Static Polymorphism)和动态多态(Dynamic Polymorphism)。静态多态主要通过函数重载(Function ...
### C++多态与虚表解析 #### 一、引言 C++作为一种强大的面向对象编程语言,提供了许多高级特性,其中包括多态性。多态性允许程序员编写更灵活、可扩展的代码,其中一个关键机制就是虚函数。本文将深入探讨C++中虚...
在这个“C++基于多态的职工管理系统”项目中,我们将深入探讨如何利用C++的面向对象特性,尤其是多态性,来构建一个高效的职工管理解决方案。 首先,我们需要理解什么是多态性。在C++中,多态性(Polymorphism)是...
这些是理解面向对象编程的关键要素,对于任何软件开发者,尤其是想要深入理解和运用C++的工程师来说,都是必不可少的知识。下面,我们将详细探讨这些主题。 首先,我们来看“多态性”(Polymorphism)。在C++中,多...
【C++多态的原理】 C++中的多态性是面向对象编程的重要特性,它允许通过同一接口调用不同对象的实现,实现了“一个接口,多种实现”的概念。多态分为类的多态性和函数的多态性。类的多态性主要体现在继承关系下,而...
在C++编程中,对象布局和多态实现是两个核心概念,它们对于理解和优化程序性能至关重要。对象布局指的是在内存中如何...虽然汇编代码的细节超出了本文的范围,但是掌握基本的汇编概念有助于深入理解C++的底层工作原理。
C++的多态性是其面向对象特性的重要组成部分,它允许通过基类的指针或引用调用派生类的成员函数,实现不同对象对同一消息的不同响应。多态的实现依赖于虚拟函数...理解这些概念是深入掌握C++面向对象编程的关键。
通过这个职工管理系统,你可以深入理解C++的面向对象特性,尤其是多态的运用。这不仅有助于提升编程技巧,还能让你更好地掌握如何在实际项目中组织和设计代码。在分析和理解源码的过程中,你可以学习到更多关于C++...