c++多态及其实现

本文探讨了C++中的多态特性,包括静态多态(重载和模板)和动态多态(虚函数和虚表)。静态多态在编译时确定,如重载通过参数列表区分;动态多态则在运行时确定,通过虚函数表调用相应函数,实现了子类对父类方法的覆盖或新增。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++是一门面向对象的语言,具有继承、封装和多态三大特性,本文我们总结一下c++中多态的特性及其实现方法。多态指的是调用同一接口,表现出不同的特性,分为静态多态和动态多态。静态多态指在编译期就能确定其特性的多态,而动态多态需要在运行时确定其特性。

静态多态

静态多态包括重载和模板两种方式。c++重载是指函数在调用时,即使调用的函数名相同,也可以根据参数列表来确定其调用对象,比如下面的代码中有四个函数,main()函数中的调用,根据参数列表的不同,可以找到对应的函数入口。

//函数1
void foo(){} 
//函数2
void foo(int x){}
//函数3
void foo(int x, float y){};
//函数4
void foo(float x, int y){};


int main(){
    foo();  //调用函数1
    foo(3); //调用函数2
    foo(3, 5.7); //调用函数3
    foo(3.8, 5); //调用函数4
}

需要说明的是,重载仅能识别参数列表不同的情况,这里也包括列表中参数类型的顺序不同,但不包括返回值的不同,比如下面的两个函数,编译器无法确定应该调用哪个函数,会出现如下图的报错。

void foo(float x, int y){};
int foo(float x, int y){return 0;};

在这里插入图片描述

c++支持重载是因为c++程序在编译后,这些原本同名的函数被编译成了不同名的函数,而相应的调用也修改为了新的函数名,因此重载在编译期就确定了其特性。
c++的模板元编程也是静态多态的一种,这在stl中有着大量应用,通过传入模板元来实现相同函数的不同处理。

动态多态

c++的动态多态主要通过虚函数和虚表来实现。所有包含需函数的类,在类的头部都有一个虚函数表指针,这个指针指向一个虚函数表,虚函数表中存储的是虚函数指针,通过虚函数指针,程序就可以调用相应的函数,如下图描述了下面代码的内存布局。

#include <iostream>
using namespace std;
 
class Base
{
	virtual void foo(){cout<<"Base::foo"<<endl;}
};
 
typedef void(*Fun)(void);
 
int main()
{	
	Base d;

    cout << "虚函数表指针地址:" << (long long*)(&d) << endl;
    cout << "虚函数指针地址:" << (long long*)*(long long*)(&d) << endl;
 
	Fun pFun = (Fun)*((long long*)*(long long*)(&d)); 
	pFun();

    return 0;
}

虚函数内存布局
上面的代码用于验证图中虚函数的内存布局,下面是代码运行的输出结果。
在这里插入图片描述

可以看到通过两次指针的消耗,应用程序成功调用了foo()函数,那么虚函数又是怎样实现多态的呢?

#include <iostream>
using namespace std;
 
class base
{
public:
	virtual void foo(){cout<<"Base::foo"<<endl;}
};
 
class derive:public base{
public:
    void foo(){cout<<"derive::foo"<<endl;}
};

int main()
{	
    base* p = new derive();
    p->foo();
    return 0;
}

上面代码的输出结果是"derive::foo",这是因为如果虚函数是子类继承自父类的虚函数,那么会对应覆盖虚表中的虚函数指针,如果是子类的虚函数,则在虚表中新增一个虚函数指针。因此在子类中重写foo成员方法会将虚表中父类的foo方法覆盖,这时即使我们通过base类实例调用,虚表中的函数也已经被重写。需要说明的是,虽然虚函数需要在运行时才确定调用的函数,虚表却早在编译阶段就已经生成。
在多继承,菱形继承等复杂情况下,内存模型还会有更复杂的变化,我们将在后续文章中继续讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值