编码踩过的坑(虚接口)

本文探讨了C++中由于虚函数调用机制导致的问题,特别是在接口类新增方法时可能引发的异常。文章指出,当在接口类中添加新的虚方法functionD时,建议将其放在已有的虚方法之后。这样做是因为虚函数通过虚表(vtbl)和虚表指针(vptrs)实现调用,如果下游模块未重新编译,调用旧的虚函数指针可能会误执行新方法,导致意外行为。在多模块协作的项目中,遵循这一原则可以避免虚表指针错误,保证程序稳定性。
摘要由CSDN通过智能技术生成
本文介绍,由于虚函数的调用机制,导致的虚函数调用异常。

C++对外提供的接口,一般以接口类的public方法体现,如下:

class interface{
public:
    virtual int functionA();
    virtual int functionB();
    virtual int functionC();
};

如果在interface中新增一个方法(比如叫functionD),那么建议将新增的方法放在最后面。这样就算使用interface接口的代码没有重新编译,也不会影响到interface中老方法的使用。

想了解其中的原因为,必须先搞清楚虚函数的调用机制。

虚函数的调用,依赖虚表(vtbl)和虚表指针(vptrs)。每个包含(或继承)虚函数的类,都有一个虚表,虚表是个指向类中各个虚函数的指针数组(或链表);
包含(或继承)虚函数类的对象,都有一个隐藏的成员,这个成员指向就是虚表指针,它指向对应类的虚表。

以上面代码中的interface类为例。如果此类的虚表叫interface_vtbl,其内容应该为:
interface_vtbl[0] 指向 interface::functionA()
interface_vtbl[1] 指向 interface::functionB()
interface_vtbl[2] 指向 interface::functionC()

那么,虚函数的调用实际是这样的:

interface obj_i;
obj_i.functionB();
// 上面一行的伪代码为:
obj_i.vptrs[1](&obj_i); // &obj_i作为functionB()的this指针
回到增加一个新的方法functionD:
class interface{
public:
    virtual int functionA();
    virtual int functionD();
    virtual int functionB();
    virtual int functionC();
};

将functionD放在functionA的后面,而interface以头文件和目标文件的形式提供给下游模块。
如果下游模块没有重新编译,而是直接链接,想想下游模块调用functionB的时候,会出现什么情况。

实际上,调用functionB的时候,会走到functionD中。

这类情况,在多个模块协作编译链接的软件项目中,可能会出现。因此在实际中,建议将新的虚方法,放在最后。这样至少在不使用新方法的一些模块中,不会出现虚表指针跑飞的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值