序言
这里我们必须明白public 继承就是is a 关系,默认子类就是父类,虽然子类有自己新添加的功能,但是基于里氏代换原则,能用到父类的地方也能间接的应用到子类。也就意味着如果保持代码干净性,父类的non-virtual 函数(子类的公有特性提取),如果该函数有变动,可以考虑设为虚函数或者继承原有的non-virtual,子类再重新添加新函数对原有继承进行修改,这样是为了确保不要重新定义继承而来的non-virtual函数,也确保里氏转换原则,否则,子类就不是父类。好接下来,我们沿着这个思路去探讨为啥不重新定义继承而来的缺省参数值。
绝不重新定义继承而来的缺省参数值
将问题简单化,我们从两种函数: virtual 与 non-virtual。
在序言中我们确定了不要重新定义而来的non-virtual函数,那么我们来从virtual函数角度去分析。
代码如下:
#ifndef TESTINHERIANCEDEFAULT_H
#define TESTINHERIANCEDEFAULT_H
#include <QString>
#include <QDebug>
/*
绝不重新定义而来的缺省默认值
*/
class TestInherianceDefault
{
public:
TestInherianceDefault();
virtual ~TestInherianceDefault(){}
virtual void output(QString info = "This is parent class")
{
qDebug() << __FUNCTION__ << " " << info;
}
};
class TestInherianceDefaultChild: public TestInherianceDefault
{
public:
TestInherianceDefaultChild(){}
~TestInherianceDefaultChild(){}
virtual void output(QString infoa = "This is child class")
{
qDebug() << __FUNCTION__ << " " << infoa;
}
};
#endif // TESTINHERIANCEDEFAULT_H
TestInherianceDefault* pParent = new TestInherianceDefaultChild;
pParent->output();
截图如下
参数输出为父类的默认缺省的。
原因
pParent 被声明为point-to-TestInherianceDefault型,他们都以他为静态类型,不论他指向TestInherianceDefaultChild,其静态类型是TestInherianceDefault* 。
virtual函数是动态绑定的,调用哪个virtual函数,依据的是调用的那个对象的动态类型,但是缺省参数值却是静态绑定的。意味着你可能调用derived class的继承而来的虚函数同时,却使用的是base class 提供的默认参数值。
主要原因是:
为了运行期效率,如果缺省值默认是动态绑定的,编译器就要在运行期为virtual函数决定合适的参数默认值,这比在编译期就决定的机制更慢还更复杂,为了提高执行速度与编译器上简易度,C++做了取舍。