静态联编:在编译阶段 就将函数的实现与函数的调用绑定起来
动态联编:在程序运行时 将函数的实现与函数的调用绑定起来
例如:
#include<iostream>
using namespace std;
class base{
public:print(){cout<<"this is base's print"<<endl;
}
};
//派生类公有继承基类
class derived:public base {
public:print(){cout<<"this is drived's print"<<endl;
}
};
int main(){
base b;
b.print();//调用了base的print
derived d;
d.print();// 调用了derived的print
base *p=&b;//p指向b
base &c=d;//c作为d 的引用
p->print();//调用了base的print
c.print();//调用了base的print
}
执行结果为
这里采用了静态的联编从而d 的引用c在调用print函数时,由于自身为base类型,调用了基类的print
为了让c在调用时使用派生类的函数,则需要对print进行虚函数的声明。
如:`
class base{
public:virtual print(){cout<<"this is base's print"<<endl;
}
};
//派生类公有继承基类
class derived:public base {
public:print(){cout<<"this is drived's print"<<endl;
}
};
int main(){
base b;
b.print();//调用了base的print
derived d;
d.print();// 调用了derived的print
base *p=&b;//p指向b
base &c=d;//c作为d 的引用
p->print();//调用了base的print
c.print();//调用了base的print
}
结果为:
再来更好地理解虚函数的运行机制:其的实际执行步骤如下:
1.定义虚函数的时候编译器自动增加了一个指针vptr 指向该虚函数地址
2.若派生类未重写虚函数,其vptr指向基类虚函数,若重写则指向自身虚函数地址
注意:
1.派生类能继承虚函数,只要与基类虚函数同名,就无需声明,直接成为虚函数
2.对虚函数使用对象指针或者引用才是动态联编,当使用对象调用时为静态联编
3.虚函数是动态成员函数
4.如果将基类析构函数定义为虚函数,其所有派生类析构函数皆为虚函数,无论同名与否
5.不支持虚构造函数