什么是联编?
联编,即绑定,就是将模块或者函数合并在一起生成可执行代码的过程,同时对每个模块或函数分配内存地址,并且对外部访问也分配正确的内存地址。
在编译阶段,实现联编的称为静态联编,又称早期联编;在运行阶段,实现的联编称为动态联编,又称晚期联编。在C++中一般是静态联编,但是重载、重写、虚函数的出现,要求动态联编的出现,因为编译器不知道用户将选择哪种类型的对象,执行具体哪一块代码。所以,编译器必须生成能够在程序运行时选择正确的虚函数的代码。即编译器对虚方法使用动态联编。
下面从一段代码中学习两者的区别:
静态联编
#include <iostream>
using namespace std;
class Point { //Point类表示平面上的点
double x,y; //坐标值
public:
Point(double x1=0, double y1=0) : x(x1),y(y1) { }//构造函数
double area() { return 0; }
};
class Circle: public Point { //Circle类表示圆
double r;//半径
public:
Ccircle(double x.double v.double r1 ):Point(x.v).r(r1)
double area(){return 3.1415926*r*r}
};
int main( )
{ Point a(2.5,2.5); Circle c(2.5,2.5,1);//Point基类对象,Circle派生类对象
cout<<"Point area="<<a.area()<<endl; //基类对象,输出0
cout<<"Circle area="<<c.area( )<<endl;//派生类对象,输出3.14
Point *pc=&c , &rc=c;//基类指针、引用指向或引用派生类对象
cout<<"Circle area="<<pc->area( )<<endl;//静态联编基类调用,输出0
cout<<"Circle area="<<rc.area( )<<endl;1//静态联编基类调用,输出0
return 0;
}
动态联编:类多态
#include <iostream>
using namespace std;
class Point { //Point类表示平面上的点
double x,y; //坐标值
public:
Point(double x1=0, double y1=0) : x(x1),y(y1) { }//构造函数
virtual double area() {return 0; }//虚函数只能是类中的成员函数,不能是静态的,virtual必须在类体里面使用!
};
class Circle: public Point { //Circle类表示圆
double r;//半径
public:
Ccircle(double x.double v.double r1 ):Point(x.v).r(r1)
double area(){return 3.1415926*r*r}
};//继承同名的虚函数(参数个数,参数类型,返回类型一致),在派生类中自动变成virtual,所以可写virtual也可不写
int main( )
{ Point a(2.5,2.5); Circle c(2.5,2.5,1);//Point基类对象,Circle派生类对象
cout<<"Point area="<<a.area()<<endl; //基类对象,输出0
cout<<"Circle area="<<c.area( )<<endl;//派生类对象,输出3.14
Point *pc=&c , &rc=c;//基类指针、引用指向或引用派生类对象
cout<<"Circle area="<<pc->area( )<<endl;//动态联编派生类调用,输出3.14
Point *pb=new Circle;
cout<<"Circle area="<<pb->area( )<<endl;//动态联编派生类调用,输出3.14
delete pb;
cout<<"Circle area="<<pc->Point::area( )<<endl;//强制使用静态联编,输出0
cout<<"Circle area="<<rc.area( )<<endl;1//动态联编派生类调用,输出3.14
return 0;
}
动态联编:类成员函数动态
#include <iostream>
using namespace std;
class Base {
public: virtual void print() {cout<<"Base "<<endl;}//虚函数};
};
class Derived: public Base {
public: void print() {cout<<"Derived" <<endl;}//虚函数};
void display (Base *p, void(Base::*pf)()){(p->*pf)();}
};//Base::*pf指向Base成员函数的指针
int main()
{
Derived d;Base b;
display(&d ,&Base::print); //输出Derived
display (&b ,&Base::print);//输出Base
return 0;
}
虚函数的调用规则是:根据当前对象,优先调用对象本身的虚成员函数。这和名字支配规律类似,不过虚函数是动态联编的,是在运行时(通过虚函数表中的函数地址)“间接"调用实际上欲联编的函数。