为什么说c++不能重定义继承而来的默认参数
2016-10-16 10:50
211 查看
目前有许多文章都会详细介绍c++虚函数实现,博主在此稍微点题,从c++的虚函数实现,简单说明下为什么说不能重定义继承而来的默认参数
在上述代码中,d的虚函数表在编译器编译时,就被动态的替换为derive::fun() 。因此在d->fun()调用的时候就能调用到子类实现。
而这个与本次话题又有什么关系呢?在effecitve c++中的第37章有说到,绝不重现定义基础而来的缺省参数。
如果将上述的类声明改为
大家猜测下实际的打印输出结果是什么呢?
答案是
为什么会出现这么诡异的输出呢,其实把上面的代码写成编译的伪代码大家就能知道原因了。
vptr是编译器生成的虚函数表,在大多数编译器下都是在类的指针地址。而虚表带定义是由于每个编译器厂家按照自己的标准实现,c++标准中未做详细的规定,所以出现类指针的第一位不是虚表地址也不要奇怪。
在编译器生成虚表的时候,默认参数是由静态绑定,编译器把符合d的默认入参写入。就是说,默认参数在编译过程中就已经决定。
所以引用effective c++中的总结,virtual函数是你唯一覆盖的东西。
最后给大家再引申一个小问题,如果把上文中的
改为
那么请问,上段代码的编译结果是什么样子的,最后由什么样的输出呢?
答案还是输出Derive::fun,大家可以结合上面的编译器伪代码思考下。
博主的这篇博客可是参考effective 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++模型总结的,如果有不对的地方,欢迎大家在博客下留言指正,谢谢。
相关文章推荐
- 读书笔记 effective c++ Item 37 永远不要重新定义继承而来的函数默认参数值
- 为什么C++赋值运算符重载函数不能被继承?
- c++设计一个不能被继承的类,为什么必须是虚继承?原因分析
- 为什么C++中的拷贝构造函数参数不能值传递
- 为什么C++赋值运算符重载函数不能被继承? 【转】
- 编程算法 - 不能被继承的类(模板参数友元) 代码(C++)
- 为什么C++赋值运算符重载函数不能被继承?
- c++设计一个不能被继承的类,为什么必须是虚继承?原因分析
- 为什么C++赋值运算符重载函数不能被继承?
- [C++] 为什么operator = 不能被继承
- Python陷阱:为什么不能用可变对象作为函数的默认参数值
- C++中结构体与类的区别(结构不能被继承,默认是public,在堆栈中创建,是值类型,而类是引用类型)good
- c++设计一个不能被继承的类,为什么必须是虚继承?原因分析
- 为什么C++赋值运算符重载函数不能被继承?
- 为什么C++赋值运算符重载函数不能被继承?
- 为什么不能使用成员变量的值作为成员函数的默认参数?
- 为什么C++赋值运算符重载函数不能被继承?
- 用C++ 设计一个不能被继承的类
- C++中如何让一个类不能被继承
- C++: VC6转VC8出现问题:error C2664: “fopen”: 不能将参数 1 从“CString”转换为“const char *”