2010-12-03 85 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。

您可能希望重新考慮執行前/後函數的方式,作爲解決問題的另一種方法:可以通過重載「 - >」運算符來實現它們。