动态绑定与虚函数
动态绑定 是与 静态绑定 相对立的概念,而绑定绑的是函数。
对于任何对象,其以函数名调用函数的时候,对于执行哪个函数是在编译时就能确定的,这叫静态绑定。
而对于指针和引用,由于C++中允许基类指针(引用)指向派生类对象,这时候其虚函数被调用,具体执行哪个函数是与引用(指针)指向的对象是什么有关,这叫动态绑定。
例子
现在定义一个基类 Person,其中有一个虚方法who:
class Person
{
public:
virtual void who() {
cout << "I am person" << endl;
}
};
然后有一个派生类 Student
class Student
{
public:
virtual void who() {
cout << "I am student" << endl;
}
};
主函数调用情况如下:
int main()
{
Student s;
Person p;
Person &a = s;
Person &b = p;
a.who();
b.who();
}
Note:
- a.who() 输出的是Student里的内容
I am student - b.who() 输出的是Person里的内容
I am Person
纯虚函数
语法规则如下:
class A
{
virtual void a() = 0;
}
- 用
=0标记该函数是个纯虚函数。
任何含有纯虚函数的类都是抽象类,抽象类不能产生对象。
注意事项
- 构造函数不可以是虚函数
- 如果一个类被继承,析构函数最好定义为虚函数,否则可能产生问题。
虚函数如何实现
下面讲一种编译器实现虚函数的方法。
- 首先编译器会给每一个对象产生一个隐藏的表:表中存储所有虚函数的地址。
- 派生类先完整继承基类的虚函数表。
- 如果派生类重载了基类的虚函数,则会用派生类重载函数的地址代替原函数的地址,如果新定义了虚函数,则把新函数的地址也加入虚函数表。
- 当以指针(引用)形式调用虚函数时,按照调用的函数的序号对应到虚函数表上对应的函数执行。如调用第2个虚函数,则实际执行的是虚函数表中第二个函数。