我的代码如下:
#include <iostream>
using namespace std;
class Base
{
public:
virtual int f(int i); // _ZN4Base1fEi
};
int Base::f(int i)
{
cout << "Base f()" << endl;
}
class Derived:public Base
{
public:
// (change) int f(int p);
int f(int *p);
};
// (change) int Derived::f(int p)
int Derived::f(int *p)
{
cout << "Derived f()" << endl;
}
int main(void)
{
Base b;
Derived d;
Base *pa, *pb;
pa = &b;
pb = &d;
pa->f(1); // Base f()
pb->f(1); // Base f()
//d.f(1); // compile error!
return 0;
}
如果我使用(change)
代码,输出将是
Base f()
Derived f()
所以(change)
代码重载Base::f()
,对于函数调用,我认为编译器应该生成这样的东西:
(*pa->vptr[1])(pa, 1) // access vtbl to get function address
(*pb->vptr[1])(pb, 1)
这是因为编译器知道Base::f()
和Derived::f()
是虚函数,对吧?所以它生成了代理vtbl的代码。
但是,如果不使用(change)
代码,则对f()
的两次调用都将访问Base::f()
,这是否意味着它仍然生成与上述相同的访问vtbl?如果它是真的,我可以假设生成代码的过程如下:
对于通过指针的函数调用,首先检查引用的指针类型(pa
或pb
),并将f()
视为<reference type>::f()
(Base::f()
此处) ,发现它是一个虚函数并生成代码。
这将导致另一个问题Derived::f()
隐藏Base::f()
class Derived
,这就是为什么d.f(1)
是错误的原因。但是pb->f(1)
可以访问Base::f()
,pb
指向Derived d
,这是否意味着pb->f(1)
可以访问隐藏的Base::f()
?那么隐藏机制不能通过指针进行函数调用吗?
由于
答案 0 :(得分:1)
这是因为编译器知道Base :: f()和Derived :: f()是虚函数,对吗?
不完全。编译器知道Base::f()
是虚拟的,如果Derived::f()
是虚拟的,在这种情况下隐藏与否是无关紧要的。你创造了一个糟糕的例子,让它自己迷惑。看看这个功能:
void f( Base *p )
{
p->f(1);
}
并尝试回答您自己的问题。也试着回答这个问题:
1编译器是否知道p
是否指向Base
或Derived
?
2如果没有,它将如何生成调用f()
的代码?
所以隐藏机制不通过指针进行函数调用吗?
隐藏机制是编译时的概念,适用于解析方法调用。您通过指向f()
的指针调用Base *
,因此编译器不关心它是否隐藏在Derived
中,它生成的代码通过Base
指针调用虚方法。 / p>
实际上,在您的情况下,优化器可能会消除虚拟表分辨率,因为它知道实际类型,但结果将完全相同。它与隐藏机制&#34;
完全无关答案 1 :(得分:0)
重载仅适用于在同一范围内定义的名称。因此,基类中的f
版本和派生类中的f
版本不是重载,这就是对d.f(1)
的调用失败的原因:没有版本{{ 1}}需要f
,因为编译器在int
中找到f(int*)
时停止查找。
其他调用有效的原因是他们正在指向Derived
,而Base
中唯一的f
版本需要Base
,所以这就是所谓的那个。
这与虚拟功能无关。如果int
不是虚拟的,或者Base::f
是虚拟的,那么它将以相同的方式工作。