转自:http://www.cppblog.com/note-of-justin/archive/2010/03/04/106351.aspx
条例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();
// ..
}
{
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..
}
//..
} ;
{
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..
}
//..
} ;