C++语言程序设计

那么，当vehicle*指向派生类对象时，我们能不能通过该指针来调用派生类的成员函数呢？在C++中，我们是可以作到的，这要用到C++的多态特性。也就是说，基类指针是调用基类的成员函数，还是调用派生类的成员函数，不是由指针的类型决定的，而是由指针指向的对象的类型决定的。
多态也称为动态联编或迟后联编，因为到底调用哪一个函数，在编译时不能确定，而要推迟到运行时确定。也就是说，要等到程序运行时，确定了指针所指向的对象的类型时，才能够确定。在C++中，动态联编是通过虚函数来实现的。
我们知道，函数调用是通过相应的函数名来实现的。对于源程序进行编译后，存放在内存中的可执行程序，函数实际上是一段机器代码，它是通过首地址进行标识和调用的。例如，假定定义一个函数：
void func()
{
//…
};
我们可以用下面的语句调用这个函数：
func(); //调用func函数
这是在源程序中调用函数的方法，它是用函数名操作的。
下面我们看看在可执行程序中函数调用是怎么操作的，我们用汇编语言来说明，因为汇编语言和机器语言（计算机可以直接执行的语言）是一一对应的。
在可执行程序中，函数调用使用下面的方法：
call [xxxxx]
xxxxx代表存放函数代码内存空间的首地址。
call是汇编语句中的一条指令，意思是调用一个函数。实际操作过程是：保存当前地址、保护现场，跳转到xxxxx地址执行。正是基于这个原因，在C/C++中的函数名是一个指针，该指针指向该函数段代码在内存中的首地址。
如何将源程序中的函数调用和函数体（也就是在内存中该函数的机器代码）联系起来呢？这件工作是由编译器和连接程序来完成的。
在C/C++语言中，函数调用在程序运行之前就已经和函数体（函数的首地址）联系起来。编译器把函数体翻译成机器代码，并记录了函数的首地址。在对函数调用的源程序段进行编译的时候，编译器知道这个函数名的首地址在那里（它可以从生成的标识符表中查到这个函数名对应的首地址），然后将这个首地址替换函数名，一并翻译成机器码。这种编译方法称为早期或静态联编。
那么，当vehicle*指向派生类对象时，我们能不能通过该指针来调用派生类的成员函数呢？从这种编译方法来看，是不可能的。因为编译器只会寻找vehicle*的成员函数。如何实现这个功能：当用基类指针调用成员函数时，是调用基类的成员函数，还是调用派生类的成员函数，不由指针的类型决定，而由指针指向的对象的类型决定呢？也就是说，如果基类指针指向基类对象，就调用基类的成员函数，如果基类指针指向派生类对象，就调用派生类的成员函数。这就要用到另外一种方法，称为动态联编或迟后联编。到底调用哪一个函数，在编译时不能确定，而要推迟到运行时确定。在C++中，动态联编是通过虚函数来实现的。下面我们先介绍虚函数，然后讨论动态联编实现的原理。