虚函数的一种替代方案

虚函数的目的是实现对象的动态绑定,但是有些情况下,可能换一种替代方案,可能会使类的设计更加稳定,易用,下面列出一个我认为很棒的虚函数的替代方案。
使用non-virtual interface(NVI)手法,它以public non-virtual 成员函数包裹较低访问性的virtual函数:

class A{
public:
    int getVal(){
        return get();
    }
private:
    virtual int get(){...}
}
class B:public A{
private:
    virtual int get(){...}
}

在代码里我们可以看到虚函数不同以往的虚函数继承措施,以往的虚函数应该是public的,然后各个派生类在各自内部以pubilc类型进行重新实现。但是上述代码中将基类中的virtual函数声明为了private类型,并用一个non-virtual函数getVal封装了虚函数get(),该non-virtual函数只在基类中实现,派生类一律继承。这样可以达到和虚函数一样的效果,一样可以进行动态绑定。那么一定会有同学问,这么皮一下很开心吗?是的,在下面说的这种情况下,很开心:

class A{
public:
    enum val{small,middle,large};
    virtual int get(val value=small){...}
}
class B:public A{
public:
    virtual int get(val value=large){...}
}
A *pa=new B();
A->get();

这个例子中,虚函数带有默认实参,我们声明A类型的指针指向一个B对象,然后调用其中的get()函数,相信十有八九众人会立刻想,虚函数!动态绑定
!可是我在编译器上实现过了,发现执行的函数是B类中的函数,但是get到的参数是A类中默认传递的参数small。这个原因是因为编译器分为静态绑定和动态绑定,也就说所谓的早绑定和晚绑定,对于虚函数,编译器确实是施以了动态绑定这个高大上的设施,但是对于其中的默认实参,编译器依然实施的是静态绑定策略。
为什么C++坚持以这种乖张的方式来运作呢?答案在于运行期效率,如果缺省值是动态绑定,编译器就必须有某种办法在运行期为virtual函数决定适当的参数缺省值。这比目前实行的“在编译期决定”的机制更慢而却更复杂。为了程序的执行速度和编译器实现上的简易度,C++做了这样的取舍,其结果就是你如今所享受的执行效率。
因此,对于虚函数,本身就不应该重定义默认实参,但是既然不能重定义默认实参,每次继承还要重新写一遍,这就给类的定义者增加了负担,也增加了出错的可能。因此对于这种情况,我们就应该祭出本文所说的新武器—NVI手法。

class A{
public:
    enum val{small,middle,large};
    int getVal(val value=small){
        return get();
    }
private:    
    virtual int get(val value){...}
}
class B:public A{
private:
    virtual int get(val value){...}
}
A *pa=new B();
A->getVal();

这个时候,我们只需要在getVal函数中设置好默认实参值,调用getVal函数的时候会转调虚函数get,get只接受getVal函数中默认实参small,保证了派生类和基类的统一性,杜绝了出错的可能。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值