因为又一次定义继承而来的non-virtual函数是不对的(见上一个条款),所以这个条款就将问题局限于:绝不又一次定义继承一个带有缺省參数值的virtual函数。

(一)

virtual函数是动态绑定的,而缺省參数却是静态绑定。

对象的所谓静态类型,是它在程序中被声明时所採用的类型。

你可能会在“调用一个定义于derived class 内的virtual函数”的同一时候,却使用了base class为它所指定的缺省參数值。

(二)

为什么继承而来的virtual函数的缺省參数值不能被又一次定义呢?

事实上原因也挺简单:缺省參数是静态绑定,而virtual函数是动态绑定. 所谓对象的静态绑定也叫前期绑定,它是说该对象类型和行为在程序编译期间就能够确定,比如:

class Shape{public:enum Color{RED,GREEN,BLUE};virtual void draw(Color color = RED)const = 0;...};class Circle : public Shape{public://哦欧! 居然改变缺省參数值virtual void draw(Color color = GREEN)const{ ... }};class Rectangle : public Shape{public://没用指定參数类型,须要用户去明白的指定其值//静态绑定下不继承基类的缺省值,若以指针或引用调用则不须要指定缺省值,由于动态绑定//继承基类的參数缺省值virtual void draw(Color color)const{ ... }};

看一下以下几个指针:

 Shape* ps;Shape* pc = new Circle;Shape* pr = new Rectangle;

这里的ps,pc,pr无论它详细指向的是什么对象,他们的静态类型都是Shape*。而动态类型就是它们真正指向的对象的类型。故pc的动态类型为Circle*,而pr的动态类型为Rectangle*,ps因为没有指向不论什么对象,所以此时没有动态类型。

(三)看以下这个语句!

pc->draw();   //注意调用的是: Circle::draw(RED)

怎么会调用Circle::draw(RED)呢!?为什么不是Circle::draw(GREEN)?
原因:

(1)首先依据其调用语句用指针这一事实,我们就知道了其调用的版本号应该是该指针的动态类型的函数版本号,即Circle::draw,这个问题不大。

(2)以下我们来看它的传值參数,前面我们提到缺省參数值是静态绑定的,而pc的静态类型是Shape*,所以该參数的传入值是Shape的该函数版本号的缺省值。

那为什么C++坚持以这种乖张的方式来运作呢?答案在于执行期效率,假设缺省值也是动态绑定的,那么编译期就必需要有办法在执行期为virtual函数决定适当的參数缺省值.假设这样做的话,就要比眼下实现的"在编译期决定"的机制更慢并且更复杂,考虑到执行速度和实现上的简易性,C++放弃了这种做法。

(四)解决方法!

如今,为了遵循本款约定却同一时候提供缺省參数值给你的基类和父类,,代码就这样了:

class Shape{public:enum Color{RED,GREEN,BLUE};virtual void draw(Color color = RED)const = 0;...};class Circle:public Shape{public:virtual void draw(Color color = RED)const {...}};

明显的是代码反复嘛!何况你要是想改变缺省值的话,必需要同一时候改变基类和子类函数的缺省值,一不小心,就会出现漏改或写错的情况,导致意想不到的错误出现.有没用一种更方便的写法呢?当然,你还记得NVI手法吗?额..,(non-virtual interface),要是忘记的话,回过头看看条款35,用这样的手法的话,我们写下代码例如以下:

class Shape{public:enum Color{RED,GREEN,BLUE};void draw(Color color = RED) const{...doDraw(color);...}...private:virtual void doDraw(Color color) const = 0;  };class Circle:public Shape{...private:virtual void doDraw(Color color){ ... }};

因为draw是non-virtual而non-virtual绝对不会被又一次改写(条款36),所以color的缺省值总是为RED。

请记住:
(1)绝对不要又一次定义一个继承而来的缺省參数值,由于缺省參数值都是静态绑定,而virtual函数-你唯一应该覆写的东西-却是动态绑定。

Effective C++:条款37:绝不又一次定义继承而来的缺省參数值相关推荐

  1. Effective C++条款09:绝不在构造和析构过程中调用virtual函数

    Effective C++条款09:绝不在构造和析构过程中调用virtual函数(Never call virtual functions during construction or destruc ...

  2. Effective C++条款粗略总结

    文章目录 Effective C++ 1.类/结构体 2.资源管理 3.实现 4.模板与泛型编程 5.定制new和delete 6.其他 Effective C++ 1.类/结构体 1.把C++看成一 ...

  3. 【Effection C++】读书笔记 条款36~条款37

    [Effection C++]继承与面向对象设计 条款36:绝不重新定义继承而来的non-virtual函数 class D由class B以public形式派生而来.如果class B定义了一个pu ...

  4. effective c++条款11扩展——关于拷贝构造函数和赋值运算符

    effective c++条款11扩展--关于拷贝构造函数和赋值运算符 作者:冯明德 重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符. 以下讨论中将用到的例 ...

  5. Effective C++ 条款34

    条款三十四:区分接口继承和实现继承 这个条款书上内容说的篇幅比较多,但其实思想并不复杂.只要能理解三句话即可,第一句话是:纯虚函数只继承接口:第二句话是:虚函数既继承接口,也提供了一份默认实现:第三句 ...

  6. effective c++条款44 将与参数无关的代码抽离templates

    effective c++条款44 将与参数无关的代码抽离templates 首先了解这个条款的含义:使用template可能导致代码膨胀,二进制码会带着重复(或者几乎重复)的代码.数据,或两者.其结 ...

  7. Effective C++ 条款02:尽量使用const,enum,inline替换#define

    Effective C++ 条款02:尽量使用const,enum,inline替换#define 用另一句话说:用编译器代替预处理器比较好. 举个例子:加入定义一个常量: #define ASPEC ...

  8. Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls)

    Effective C++条款05:了解C++默默编写并调用哪些函数(Know what functions C++ silently writes and calls) 条款05:了解C++默默编写 ...

  9. Effective C++条款40:明智而审慎地使用多重继承(Use multiple inheritance judiciously)

    Effective C++条款40:明智而审慎地使用多重继承(Use multiple inheritance judiciously) 条款40:明智而审慎地使用多重继承 1.多重继承的两个阵营 2 ...

最新文章

  1. 裴健:搜索皆智能,智能皆搜索
  2. bigdecimal类型数据的min方法
  3. 百度语音识别demo:去掉离线识别功能
  4. Haddop学习:(一)序
  5. PHP中使用ActiveMQ实现消息队列
  6. 酷狗音乐怎样复制歌词到计算机,酷狗怎么复制歌词和歌曲到mp3上
  7. PHP-代码审计-ini配置文件
  8. Coolpad Y1刷机方法
  9. list 相加_Python 基础 list类、运算符
  10. 请求重定向与请求转发的区别
  11. 20.docker events
  12. python 拼音相似度_人工智能之pypinyin jieba gensim 之最简单的相似度实现
  13. 学计算机的管理层,毕业很吃香、高薪岗位多的4个专业,计算机科学上榜,你的专业呢...
  14. 组合数学 8种盒子放球问题
  15. Django DTL模板使用
  16. 计算机连接公用网络受限,电脑连接无线网络受限怎么解决【解决方法】
  17. Java程序员不得不了解的5款IDE神器
  18. tree.js 酷炫的效果,人脸识别签到思路,html5 3D微信头像自动抽奖代码
  19. 什么是用计算机的主存,计算机的主存储器是指什么
  20. java json parser_自己实现JSON解析器 JsonParser

热门文章

  1. pandoc讲html转换为pdf,将HTML表格转换为PDF的Pandoc会导致非包装表格
  2. java可以做苹果软件吗_Java应用软件iPhone上运行 苹果没兴趣Sun单干
  3. 单纯形法只有两个约束条件_教学 | 线性规划 7 :单纯形法的引入
  4. oracle修改字段长度sql_Oracle RAC修改参数文件位置
  5. java命令添加classpath_java和javac命令的classpath用法
  6. 茶百科 android代码,基于android平台手机茶百科开发设计---学位论文.doc
  7. img标签 三种获取数据方式
  8. linux make
  9. MySQL Date and Time Functions(日期和时间)
  10. MySQL Encryption and Compression Functions(加密)