读书笔记:Effective C++ 炒冷饭 - Item 36 & 37 关于继承来的非虚函数和默认参数……

读书笔记:Effective C++ 炒冷饭 - Item 36 & 37 关于继承来的非虚函数和默认参数……

[原创文章欢迎转载,但请保留作者信息]
Justin 于 2010-01-26

条例36很简短,切勿重写继承来的非虚函数。看了看也就一句话能说明白的事:对于父类的非虚函数,子类老老实实继承即可,不要重写覆盖。道理确是很简单,如果是可以重新定义的函数,人家自然会用虚函数;如果用的是非虚函数,明摆着就是不让你乱动嘛@#¥%

接下来的37也不难理解:不要试图修改继承来的虚函数的默认参数。原因嘛,要记录一下,大师说了:

  • 虚函数是动态绑定的,或者说是执行期确定的。
    函数(包括虚函数)的默认参数是静态绑定的,或者说是编译期确定的。
  • 所以我们可以写出和父类不一样的虚函数实现,
    但是不能指定另外一个和父类函数默认参数不一样的默认参数。

有点拗口,没时间编例子了,就还是看代码吧:

class  AClass
{
   
public :
      
virtual   void  func(  int  param  =   123  )
      
{
         
// ..
      }

   
// ..
}
;

class  AClassDerived :  public  AClass
{
   
public :
      
//  problematic overwriting the default parameter..
       virtual   void  func(  int  param  =   456  )
      
{
         
// ..
      }

   
// ..
}
;

int  main()
{
   AClass 
*  pA  =   new  AClassDerived;
   pA
-> func();
   
// ..
}

在上面的代码中,由于函数默认参数的静态绑定特性,pA->func()执行时param事实上被赋予了123,而非子类中期望的456,虽然接下来执行的是子类的函数实现……
为什么函数默认参数不能是动态绑定的呢?因为C++考虑到执行效率和复杂性方面的代价,规定了只能是静态绑定的。(不是我胡诌,还是大师说的)

原因说了,该记解决方式了:
结合35课上学到的知识,我们可以用非虚函数接口(NVI)来解决这个问题,看代码
class  AClass
{
   
public:
      
void func(int param = 123)
      
{
         funcImpl(param);
      }

   
private:
      
virtual void funcImpl( int real_param ) = 0;
   
//..
}
;

class  AClassDerived :  public  AClass
{
   
private:
      
virtual void funcImpl( int real_param )
      
{
         
//do whatever you feel like to do here..
      }

   
//..
}
;
对默认参数的设定放在了一个非虚函数中,这样一来,就不会有以上说的顾虑了。

你可能感兴趣的:(读书笔记:Effective C++ 炒冷饭 - Item 36 & 37 关于继承来的非虚函数和默认参数……)