一篇文章带你掌握C++虚函数的来龙去脉
背景
C++中的虚函数是一个较为复杂的概念,但又是一个非常重要的特性。在C++中,新手程序员非常容易出现“虚函数”与“普通函数”的混淆,不理解其来龙去脉,导致代码出现各种问题。本篇文章将系统地介绍C++虚函数的基础知识,包括虚函数的用途,实现原理,虚函数表,以及多重继承等问题,帮助读者全面掌握C++虚函数的来龙去脉。
虚函数的用途
在C++中的虚函数主要有两个作用:
-
实现运行时多态(Runtime Polymorphism):通过使用虚函数,实现基类和派生类之间的运行时多态。
-
实现动态绑定(Dynamic Binding):使用虚函数,可以解决使用基类指针或引用时无法正确调用派生类函数的问题。
虚函数实现原理
在C++中,虚函数的实现依赖于虚函数表(Virtual Table)的概念。虚函数表是一个包含一系列指向虚函数的指针数组。这个数组存放在对象或者类的只读数据段中,每个类拥有一个对应的虚函数表,存放着该类所定义的虚函数指针。当类的某个对象被实例化时,对象会向父类索要虚函数表指针,并把它的虚函数表指针指向该表。
当调用一个对象的虚函数时,实际上是通过对象指针的虚函数表指针找到该表,根据虚函数在表中的偏移量,得到该函数的地址进行调用。
虚函数表
虚函数表是由编译器自动生成,存储在只读数据段中。虚函数表存储着一堆指向虚函数的指针,每一个在类中定义的虚函数,都被分配一个指针在虚函数表中。派生类的虚函数表中都有一个和基类虚函数表相同的前缀,以保证虚函数在继承中的正确性。
多重继承中的虚函数问题
当类继承至少两个基类,并且这些基类都定义了同名的虚函数时,派生类将会有多个虚函数表,每个虚函数表对应基类的虚函数表。派生类的虚函数表是由基类的虚函数表构成的,这个基类的虚函数表是第一次在继承体系中出现该函数的虚函数表。这就意味着,如果一个派生类对象通过一个基类对象指针访问它的同名虚函数,那么该基类虚函数表中的函数将被执行,不是派生类虚函数表中的函数。
示例说明
下面的代码示例演示了虚函数的使用,以及基类指针调用派生类的虚函数:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void func()
{
cout<<"This is Base::func()"<<endl;
}
};
class Derived:public Base
{
public:
void func()
{
cout<<"This is Derived::func()"<<endl;
}
};
int main()
{
Base *b1=new Base();
Base *b2=new Derived();
b1->func();
b2->func();
return 0;
}
执行输出结果:
This is Base::func()
This is Derived::func()
在上面的代码中,我们定义了一个基类Base
和一个派生类Derived
。在Base
类中,我们定义了一个虚函数func
,之后在Derived
类中重写了基类函数func
。在主函数中,我们通过基类指针调用了基类和派生类的函数。结果表明,通过基类指针调用派生类的虚函数后,会动态绑定到派生类的虚函数,实现了多态的功能。
下面的代码示例演示了多重继承中的虚函数问题:
#include<iostream>
using namespace std;
class Base1
{
public:
virtual void func()
{
cout<<"This is Base1::func()"<<endl;
}
};
class Base2
{
public:
virtual void func()
{
cout<<"This is Base2::func()"<<endl;
}
};
class Derived:public Base1,public Base2
{
public:
void func()
{
cout<<"This is Derived::func()"<<endl;
}
};
int main()
{
Base1 *b1=new Derived();
Base2 *b2=new Derived();
b1->func();
b2->func();
return 0;
}
执行输出结果:
This is Derived::func()
This is Derived::func()
在上面的代码中,我们定义了两个基类Base1
和Base2
,在这两个基类中定义了相同的函数func
。然后我们定义了一个派生类Derived
,并继承了这两个基类。在Derived
类中我们重写了基类函数func
。
在主函数中,我们用Base1
和Base2
类型的指针分别指向派生类对象。实验结果表明,两次调用都是执行的派生类的虚函数。这是因为多重继承使得Derived
类存在两个虚函数表,而使用基类指针调用虚函数时,靠前的基类虚函数将被执行。因此,在上面的代码中,两个指针都指向了派生类的虚函数表中的函数,所以两次输出结果一致。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一篇文章带你掌握C++虚函数的来龙去脉 - Python技术站