2010-12-03 87 views
5

请考虑下面的代码。通过函数指针静态调用虚函数

#include <iostream> 
#include <memory> 

struct A { 
    A() {} 
    virtual void f() { 
    std::cout << "A::f" << std::endl; 
    } 
private: 
    A(const A&); 
}; 

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    call(&A::f); 
    } 
private: 
    void call(void (A::*aMethod)()) { 
    // ... 
    (static_cast<A&>(*this).*aMethod)(); 
    //(static_cast<A>(*this).*aMethod)(); -> not allowed to copy! 
    // ... 
    } 
}; 

void main() { 
    std::auto_ptr<B> b (new B); 
    b->f(); 
} 

此代码递归调用相同B::f方法,直到用完栈,而我想call方法调用A::f。也就是说,它应该静态地调用它,因为它会一般发生过,我只是写:

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    // ... 
    A::f(); 
    // ... 
    } 
}; 

我想有call方法是前因素一些代码和“静态调用”这是常见的后原因以f ...

如何静态调用在运行时决定的虚拟函数?

+0

在`B :: f`中,为什么你必须通过`call`和一个函数指针调用函数?为什么你不能只是`A :: f();`? (将“之前”和“之后”代码重构为一些常用函数或普通类) – 2010-12-03 13:08:48

+0

这可能是我必须做的......方法`call`就是在这里来分解代码,但我有没有意识到我不能使用它,因为我打算...... – 2010-12-03 13:34:15

回答

4

这是预期的。对象表达式是对Base类A的引用,因此虚拟函数机制(动态绑定)被触发,因为A :: f是虚拟的。

只有::运算符可以处理虚拟函数调用机制。

$ 10.3/12- “与 范围操作者(5.1)显式资格抑制 虚拟调用机制”。

+0

看来我不能在这里使用范围操作符:它会限定指针的名称,而不是指向的功能... – 2010-12-03 13:26:07

1

您的覆盖在您使用指针时得到解决,所以您在这里想要的东西不容易以这种方式实现。你可以做的最好的事情就是调用你的函数的包装器 - 可以是外部函数,也可以是调用函数的非虚函数。如果你有C++ 0x功能,你可以使用最干净的解决方案IMO的lambda。

您可能希望重新考虑执行前/后函数的方式,作为解决问题的另一种方法:可以通过重载“ - >”运算符来实现它们。