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

来源:互联网 发布:开淘宝店可以兼职吗 编辑:程序博客网 时间:2024/05/02 04:40

目前有许多文章都会详细介绍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 0