为什么说c++不能重定义继承而来的默认参数

目前有许多文章都会详细介绍c++虚函数实现,博主在此稍微点题,从c++的虚函数实现,简单说明下为什么说不能重定义继承而来的默认参数

class Base
{
public:
    virtual void fun()
    {
        std::cout << "Base::fun()" <<std::endl;
    };
};

class Derive : public Base
{
public:
    virtual void fun()
    {
        std::cout << "Derive::fun()" << <<std::endl;

    };
};

int main()
{
    Base *d = new Derive;
    d->fun();
    return 0;
}

在上述代码中,d的虚函数表在编译器编译时,就被动态的替换为derive::fun() 。因此在d->fun()调用的时候就能调用到子类实现。

而这个与本次话题又有什么关系呢?在effecitve c++中的第37章有说到,绝不重现定义基础而来的缺省参数。
如果将上述的类声明改为

class Base
{
public:
    virtual void fun(int i = 1)
    {
        std::cout << "Base::fun, i = " << i <<std::endl;
    };
};

class Derive : public Base
{
public:
    virtual void fun(int i = 2)
    {
        std::cout << "Derive::fun , i = " << i <<std::endl;

    };
};

大家猜测下实际的打印输出结果是什么呢?

答案是

Derive::fun , i = 1

为什么会出现这么诡异的输出呢,其实把上面的代码写成编译的伪代码大家就能知道原因了。

(*d->vptr[0])(d, 1);

vptr是编译器生成的虚函数表,在大多数编译器下都是在类的指针地址。而虚表带定义是由于每个编译器厂家按照自己的标准实现,c++标准中未做详细的规定,所以出现类指针的第一位不是虚表地址也不要奇怪。

在编译器生成虚表的时候,默认参数是由静态绑定,编译器把符合d的默认入参写入。就是说,默认参数在编译过程中就已经决定。
所以引用effective c++中的总结,virtual函数是你唯一覆盖的东西。

最后给大家再引申一个小问题,如果把上文中的

class Derive : public Base
{
public:
    virtual void fun(int i = 2)
    {
        std::cout << "Derive::fun , i = " << i <<std::endl;

    };
};

改为

class Derive : public Base
{
private:
    virtual void fun(int i = 2)
    {
        std::cout << "Derive::fun , i = " << i <<std::endl;

    };
};

那么请问,上段代码的编译结果是什么样子的,最后由什么样的输出呢?

答案还是输出Derive::fun,大家可以结合上面的编译器伪代码思考下。

博主的这篇博客可是参考effective c++和深度探索c++模型总结的,如果有不对的地方,欢迎大家在博客下留言指正,谢谢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值