您的位置:首页 > 编程语言 > C语言/C++

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

2016-10-16 10:50 211 查看
目前有许多文章都会详细介绍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++模型总结的,如果有不对的地方,欢迎大家在博客下留言指正,谢谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: