通过指针调用c ++函数可以访问隐藏的基类成员函数吗?

时间:2016-11-03 16:25:03

标签: c++ virtual

我的代码如下:

#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?如果它是真的,我可以假设生成代码的过程如下: 对于通过指针的函数调用,首先检查引用的指针类型(papb),并将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()?那么隐藏机制不能通过指针进行函数调用吗?

由于

2 个答案:

答案 0 :(得分:1)

  

这是因为编译器知道Base :: f()和Derived :: f()是虚函数,对吗?

不完全。编译器知道Base::f()是虚拟的,如果Derived::f()是虚拟的,在这种情况下隐藏与否是无关紧要的。你创造了一个糟糕的例子,让它自己迷惑。看看这个功能:

void f( Base *p )
{
     p->f(1);
}

并尝试回答您自己的问题。也试着回答这个问题:

1编译器是否知道p是否指向BaseDerived

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是虚拟的,那么它将以相同的方式工作。