简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。
先来看一个例子。
class Base
{
public:
Base(int a):ma(a){cout<<"Base()"<show(); // call Base::show 静态绑定=>编译时期的绑定
/*
mov ecx, dword ptr[pb]
mov eax, dword ptr[ecx]
call eax 动态绑定=》运行时的绑定
*/
// 函数调用的汇编
cout<
用对象直接调用虚函数,是静态绑定,与普通函数相同。
指针(引用)调用虚函数,是动态绑定,指向的对象调用。
在编译阶段,有虚函数会生成虚函数表,存于数据段,并且一个类型生成一个虚函数表。
虚函数表

定义一个空类,里面没有任何成员变量和成员函数,对该类求sizeof,得到的结果是多少呢?
答案是1,空类型的实例中不包含任何信息,本来求sizeof为0,但是当我们声明该类型的实例的时候,它必须在内存中占有一定空间。
如果在该类型中添加一个虚函数呢?
C++编译器一旦发现一个类型中有一个虚函数,就会该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针所以sizeof为4。
能被声明为虚函数的两个必要条件:
必须有函数符号产生 //才能将函数地址存入虚函数表中
必须已经有对象或者依赖对象 // 对象才会有虚函数指针,才能找到虚函数表
内联函数不能作为虚函数,不产生函数符号
静态方法不能作为虚函数,没有this指针,不依赖对象
构造函数不能作为虚函数,此时对象还没有生成。
虚函数编译时期确定函数名,并且压参数。
class A
{
public:
virtual void Fun(int number = 10)
{
std::cout<<"A::with number "<<number;
}
};
class B :public A
{
virtual void Fun(int number = 20)
{
std::cout<<"B::with number "<<number;
}
};
int main()
{
B b;
A &a = b;
b.Fun();
a.Fun();
return 0;
}
此程序片段输出为:
B::witn number 20
B::with number 10