静态类型:对象在声明时采用的类型,在编译期既已确定;
动态类型:通常是指一个指针或引用目前所指对象的类型,是在运行期决定的;
静态绑定:绑定的是静态类型,所对应的函数或属性依赖于对象的静态类型,发生在编译期;
动态绑定:绑定的是动态类型,所对应的函数或属性依赖于对象的动态类型,发生在运行期;
1、
class B{
public:
void vfun(int i=10)
{
qDebug() << "B:" << i;
}
};
class D: public B{
public:
void vfun(int i=20)
{
qDebug() << "D:" << i;
}
};
int main(int argc, char *argv[])
{
D* pD=new D(); // pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB=pD; // pB的静态类型是它声明的类型B*,动态类型是pB所指的对象pD的类型D*
pD->vfun(); //pD的动、静态类型都是D*,因此调用D::vfun();
pB->vfun(); //pB的静态类型永远都是B*,不管其指向的是哪个子类,都是直接调用B::vfun();
}
运行结果
D: 20
B: 10
2、
class B{
public:
virtual void vfun(int i=10)
{
qDebug() << "B:" << i;
}
};
class D: public B{
};
int main(int argc, char *argv[])
{
D* pD=new D(); // pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB=pD; // pB的静态类型是它声明的类型B*,动态类型是pB所指的对象pD的类型D*
pD->vfun(); //pD的动、静态类型都是D*,但是D类中没有找到vfun()函数,因此调用基类中的vfun()函数。
pB->vfun(); //pB的静态类型是B*,因为在B类中vfun()定义的是虚函数virtual。所以要先在子类中寻找,但是子类中没有重新定义,所以调用基类中的B::vfun()函数。
}
运行结果
B: 10
B: 10
3、
class B{
public:
virtual void vfun(int i=10)
{
qDebug() << "B:" << i;
}
};
class D: public B{
virtual void vfun(int i=20)
{
qDebug() << "B:" << i;
}
};
int main(int argc, char *argv[])
{
D* pD=new D(); // pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB=pD; // pB的静态类型是它声明的类型B*,动态类型是pB所指的对象pD的类型D*
pD->vfun(); //pD的动、静态类型都是D*,调用D::vfun()函数
pB->vfun(); //pB的静态类型是B*,因为在B类中vfun()定义的是虚函数virtual。所以要先在子类中寻找,调用D::vfun()函数
}
运行结果
D: 20
D: 10
注意:此例中pB->vfun()虽然调用的是子类D::vfun()函数,但是缺省参数 i 用的确实基类中 i 的缺省值10。这就造成了逻辑的混乱。
这里只给出建议:
绝对不要重新定义一个继承而来的virtual函数的缺省参数值,因为 缺省参数值都是静态绑定 (为了执行效率),而virtual函数却是动态绑定。
参考:https://www.cnblogs.com/AndyJee/p/4575670.html
https://www.cnblogs.com/lizhenghn/p/3657717.html