C++虚函数的实现机制
说起虚函数想必大家不会陌生,这可是多态的实现基础,没有它就白瞎了。多态也就是运行时绑定,个人对静态和动态语言之间的差别研究不深,但在鄙人看来,其实动态语言也没有那么神奇的,静态语言只不过是代码区的调用在编译期就已经完全绑定了,而动态函数可以实现在运行期动态绑定。能在运行期动态绑定必然是好的,可以提供更大的灵活性,但是天下没有免费的午餐,想要动态绑定必然需要耗费额外的空间存储一些额外的用于动态跟踪的信息和额外的绑定时间。从后面的对虚函数实现机制中我们可以窥其一二。
一、函数调用机制
首先我们需要明白的一点事,函数是如何调用的,调用函数时发生了什么?这很重要,这里我的理解是,通常情况下C/C++中函数被放入内存中的代码区,是只读的(不允许修改,能修改那就会很强大,但势必带来性能的牺牲),而函数中存储的的只是一套'计算规则'(也可以称之为一套协议,比如一套菜谱,他告诉你有了原料之后如何进行有效的烹饪),里面没有任何实实在在的变量,下面举例说明:
static int id = 0;
void getName(char *name)
{
//获取ID
int myId = id++;
//初始化后缀Buffer
char namePostfix[20];
memset(namePostfix,0,20*sizeof(char));
//计算名字长度
int len = strlen(name);
//设置后缀连接符
name[++len] = '_';
//获取后缀的字符串格式
itoa(myId,namePostfix,10);
//计算后缀的长度
int pLen = strlen(namePostfix);
//后缀拼接到名字末尾
memcpy(name+len+1,namePostfix,pLen);
name[len+pLen+1] = '\0';
}
当有用户A调用函数getName时,首先它应当事先知道函数的入口地址,也就是函数代码放在哪儿了,然后才能读到这一行代码,读到每一行时其行为如下:
(1) 读到第5行时,它了解到我应当声明一个局部变量myId,这是自己的东西,与其他人调用是毫无关系,互不影响,好比你读到菜谱时,加少许盐一样,盐是你自己的,菜谱可不负责提供盐,他只负责指导你下一步该干嘛。好了声明之后,将id左自增运算,等等,这是你会想,这个没叫我自己买啊,那什么意思,很明显这个作料买不到&#x