将源代码中的函数调用解释为执行特定的函数代码块被称为函数名联编。
在c语言中,因为每个函数名都有对应一个不同的函数。在C++中,由于重载的缘故,编译器必须查看函数参数以及函数名才能确定使用的是哪个函数,然而睡佳佳编译器可以在编译过程中完成这种两边在编译过程中进行联编,被称为静态联编。虚函数是这项工作变得更加困难,使用哪一个函数不是是不能在编译的时候确定的,因为编译器不就多少用户将选择哪种类型的对象,所以编译器必须生成能够在运行程序中时选择正确的序方法的代码,这种称为动态联编。
1.静态联编
静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差。
通过对象指针进行的普通成员函数的调用,仅仅与指针的类型有关,而与此刻指针正指向什么对象无关。要想实现当指针指向不同对象时执行不同的操作,就必须将基类中相应的成员函数定义为虚函数,进行动态联编。
class A
{
public:
void f() { cout << "A" << " "; }
};
class B :public A
{
public:
void f() { cout << "B" << endl; }
};
void main()
{
A *pa;A a; B b;
pa = &a;
pa -> f();
pa = &b;
pa -> f();
}
2.动态联编
动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低。动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数。
实现动态联编需要同时满足以下三个条件:
- 必须把动态联编的行为定义为类的虚函数。
- 类之间应满足子类型关系,通常表现为一个类从另一个类公有派生而来。
- 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
这时候我们把基类中的声明为虚函数
class A
{
public:
virtual void f() { cout << "A" << " "; }
};
class B :public A
{
public:
void f() { cout << "B" << endl; }
};
void main()
{
A *pa;A a; B b;
pa = &a;
pa -> f();
pa = &b;
pa -> f();
}
如果基类中没有将函数声明为虚函数,pa->f()将根据指针类型调用基类的函数,指针类型在编译时已知。如果将基类中的方法函数声明成虚函数,那么pa->f()根据对象类型调用函数。通常只有在运行程序的时候才能确定对象的类型,所以编译器生成的代码将在程序执行,时根据对象的类型关联,编译器对虚方法使用动态联编。