关于C++内部如何实现多态,对程序员来说即使不知道也没关系,但是如果你想加深对多态的理解,写出优秀的代码,那么这一节就具有重要的意义。 我们知道,函数调用实际上是执行函数体中的代码。函数体是内存中的一个代码段,函数名就表示该代码段的首地址,函数执行时就从这里开始。说得简单一点,就是必须要知道函数的入口地址,才能成功调用函数。
找到函数名对应的地址,然后将函数调用处用该地址替换,这称为函数绑定,或符号决议。
一般情况下,在编译期间(包括链接期间)就能完成符号决议,不用等到程序执行时再进行额外的操作,这称为静态绑定。如果编译期间不能完成符号决议,就必须在程序执行期间完成,这称为动态绑定。
非虚成员函数属于静态绑定:编译器在编译期间,根据指针(或对象)的类型完成了绑定。
而对于虚函数,知道指针的类型也无济于事。假设 func() 为虚函数,p 的类型为 A,那么 p->func() 可能调用 A 类的函数,也可能调用 B、C 类的函数,不能根据指针 p 的类型对函数重命名。也就是说,虚函数在编译期间无法绑定。
为什么虚函数在编译期间无法绑定?
因为我不知道运行期的状态啊
拿一个最简单的例子:
class BaseItem{
public:
virtual void itemMethod()=0;
};
class ItemA:BaseItem{};
class ItemB:BaseItem{};
class ItemC:BaseItem{};
while(nullptr != (rawData = readRawData())){
BaseItem* pItem = nullptr;
switch(rawData->head){
case ItemTypeA:{
pItem = new ItemA(rawData);
}break;
case ItemTypeB:{
pItem = new ItemB(rawData);
}break;
case ItemTypeC:{
pItem = new ItemC(rawData);
}break;
default:{}
}
if(nullptr != pItem){
ItemCollection.insert(pItem);
}
}
for(auto it : ItemCollection){
it->itemMethod();
}
很明显,我在编译期是无法得知容器中对象类型的,那么当我需要对容器中对象进行批量操作的时候,多态就是唯一的选择了。对于最后的for循环,无论你做什么,你都无法在编译期将其展开,只能在运行期根据实际的类型情况调用不同的函数。