前几天在北京听了一个百度大牛的技术分享会,虽然分享的是OC,但是在言谈举止间谈到了C++ virtual函数的调用问题,让我很不解,现在好好的说一下:
C++中函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;第二,必须通过基类类型的引用或者指针函数进行调用。要理解这一要求,需要理解在使用继承层次中某一类型的对象的引用或者指针的时候会发生什么。
1.从派生类到基类的转换
因为每一个派生类对象都包含基类部分,所以可将基类类型的引用绑定到派生类对象的基类部分,也可以用指向基类的指针指向派生类对象。
因为可以使用基类类型的指针或者引用来引用来引用派生类对象,所以,使用基类类型的引用或者指针时,不知道指针或者引用所绑定的对象的类型:基类类型的引用或者指针可以引用基类类型对象,也可以引用派生类的对象。无论实际对象具有那种类型,编译器都将它们当做是基类类型对象。将派生类对象当做基类对象是安全的,因为每个派生类对象都拥有基类子对象。而且,派生类继承基类的操作,即,任何可以在基类对象上的操作也可以通过派生类对象使用。
(注释:基类类型引用和指针的关键点在于静态类型和动态类型)
2.可以在运行时确定virtual函数的调用
将基类类型的引用或者指针绑定到派生类对象对基类对象没有影响,对象本身不会改变,仍然为派生类对象。对象的实际类型可能不同于该对象引用或指针的静态类型,这是C++种动态绑定的关键。
通过引用或者指针调用虚函数时,编译器将生成代码,在运行时确定调用哪个函数,被调用的是与动态类型相对应的函数。例如,我们看下面的函数:
void print_total(ostream &os,const Item_basev&item,size_t n)
{
os<<item.book()<<item.net_price(n)<<endl;
}
因为item形参是一个引用且net_price()是虚函数,item。net_price(n)所调用的net_price()版本取决于在运行时绑定到item形参的实参类型:
item_base base;
bulk_item derived;
print_total(cout,base,10);
print_total(cout,derived,10);
在第一个调用中。item形参在运行时绑定到item_base类型的对象,因此print_total内部调用item_base中定义的net_price版本。在第二个调用中,item形参绑定到bulk_item类型的对象,从print_total调用的是bulk_item类定义的net_price版本。
下一篇继续,去上课啦啦啦啦啦!!!