虚函数的一些解释

C++的行为规定是,

每个有虚函数的类,会有一张虚函数指针表,这张虚函数指针表指向最后实现的虚函数。

用指向派生类的基类指针调用函数时就会访问这张表。

从而体现了C++的多态技术,即指向派生类的基类指针可能有多种形态,

编译器并不在编译阶段决定这类指针指向的函数的具体位置,

而是在运行时通过查虚函数表的方式找到调用入口。

 

但是编译器也不是傻的,对于虚函数这一块可以做一些优化。

理论上所有基类指针所指向的虚函数都可以在编译阶段决定。

编译器并不需要每个都要等到运行的时候才去查表,对于一些直接调用编译器可以直接连接过去。

例如

A-》B(A中用一个基类指针调用了B)

所以对于这种情形我们并不用担心虚函数会影响性能。

 

但是对于一些间接的调用,则可能不得不查表了,否则会发生什么事呢?

我们看

A{1,N}-》B-》C,(A传了一个基类指针给B,然后B用这个指针调用了C。)

A{1,N}-》B的调用可以在编译阶段直接决定,但是B-》C就不好说,准确来讲这里有N种情况会发生,

如果B-》C的虚函数调用要再在编译阶段决定,那么一种最简单的做法就是,对B的代码做N份拷贝,

然后对调用C的地方做些修改就好了。

不使用虚函数表,这种最简单的情形,就使得编译后的机器码多了(N-1)份B的代码。

如果是A-》B-》C-》D,或者更复杂的情况呢,显然这种做法是不明智的。

提高代码的复用率,这也是虚函数存在的一个重要原因。

虽然带来一些性能上损失(查虚函数表),但是这个操作是常数复杂度的,

所以对于调用路径上有高复杂度的过程来说,这些损失完全可以忽略,

再加上编译器自身的优化,虚函数妥妥的。

 

虚函数除了提供多态机制外,对最终用户来说其他情形跟普通成员函数的行为一样。

也是被子类继承,也可以在子类指定namespace进行调用。

 

类的继承可以看做一个树结构,菱形也可以拆点变成树结构,最终的派生类是根部。

根据继承顺序,基类依次作为根部的叶子节点。对这棵树做先序遍历,

将每个基类定义的虚函数表,拿出来拼在一起,形成最终派生类的虚函数表。

 

更详细的内容见:

http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值