或许你做不对下面这题

2013年4月11日 由 Creater 留言 »
#include <iostream>
using namespace std;

class A{
public:
	virtual int fun(int i = 1);
};
int A::fun(int i){return i + 1;}
class B:public A{
public:
	virtual int fun(int i = 10);
};
int B::fun(int i){return i;}
int main()
{
	A *p = new B();
	cout << p->fun();
	delete p;
  return 0;
};

上面这段代码输出值是多少?

或许出乎你的意料为1.我们知道使用基类的指针,可以实现动态绑定,也就算多态。但是函数的默认参数呢,会不会发生动态改变?
使用p来调用函数func,的确会调用B类的func函数,但是默认参数还是使用基类A的默认参数。

先说一下现在的C++的参数传递机制,非虚函数和虚函数的传递机制都是一样的。
比如如下函数调用:
func(10) ;
会被编译器翻译成:
push 10
push 返回地址
call func
大概就是这样:先把参数压栈,然后压返回地址,在调用函数。
对于虚函数来说,如果调用时没有指定参数值,那么编译器会帮我们加上去。
这里就有问题来了,如果是用基类指针调用的虚函数,我们知道,因为动态绑定,编译器暂时无法知道实际调用的是哪个函数,此指针操作在实际的类地址中找到虚函数表,再根据偏移找到实际的函数跳转地址,而此时,编译器必须提前把参数压栈准备好,call之后就直接用参数了。
那么,既然编译器还不知道实际调用的是哪个函数,那么当然就更不知道实际传递的默认参数应该是子类还是父类的了。关键就在这里。
参数都是静态绑定的,如果要动态,效率会跟虚函数调用一样稍微有点低,所以C++折中了。

可以参考effective c++中的内容。

广告位

发表评论

你必须 登陆 方可发表评论.