#include <iostream>
class Base {
public:
virtual void f(int a = 1)
{
std::cout << "Base:: " << a << std::endl;
}
};
class Derived: public Base {
public:
virtual void f(int a = 2)
{
std::cout << "Derived:: " << a << std::endl;
}
};
int main()
{
Base *basep = new Derived;
basep->f();
system("pause");
return 0;
}
输出结果:
Derived::1
分析:
默认实参在编译时确定,而函数调用在运行时确定;调用基类版本的virtual函数,会使用基类的默认实参;
如果是
Derived *basep = new Derived;
basep->f();
则输出结果为:
Derived::2
C++迟绑定实现机理(编译器都是类似于此种方式实现的):
1、为每个含有虚函数的类(基类以及派生类)都创建一张虚函数表(VTable,存储于常量区),依次存放虚函数的地址。对于派生类来说,如果没有重写其基类的虚函数,那么,将会在VTable中存放基类的虚函数地址。
2、为每个含有虚函数的类的对象,创建一个指针(VPtr),指向这个类的虚函数表(所以说,同类对象的
VPtr的值是一样的,也就是说,虚函数,在这一点上,类似于类的static函数,是所有对象共有的。)
3、通过强制转换将派生类对象的地址/引用 赋给基类指针/变量(也就是向上类型转换UpCasting)
4、然后,通过基类指针/引用对象 来调用虚函数(即:polymorphic call),就会通过此时基类对象的VPtr指针在所指向虚函数表中寻址(一般是从表头地址开始,加上一定的偏移量)找到相应的函数地址,也就是之前派生类VPtr指针指向的虚函数表的函数地址。