2012-04-15 89 views
4

對我來說,它看起來很安全在此代碼投下void(Derived::*)()void(Base::*)(),如:爲什麼我不能將指向派生類成員函數的指針轉換爲相同的Base類?

#include <iostream> 
#include <typeinfo> 
using namespace std; 
struct Base{ 
    void(Base::*any_method)(); 
    void call_it(){ 
     (this->*any_method)(); 
    } 
}; 
struct Derived: public Base{ 
    void a_method(){ 
     cout<<"method!"<<endl; 
    } 
}; 
int main(){ 
    Base& a=*new Derived; 
    a.any_method=&Derived::a_method; 
    a.call_it(); 
} 

但是,編譯器抱怨投在a.any_method=&Derived::a_method;。這是阻止微妙編程錯誤的障礙,還是讓編譯器編寫者更容易生活的一個障礙?有沒有解決方法讓Base類有一個指向成員函數Derived沒有類型知識(也就是說,我不能讓Base模板參數Derived模板)。

回答

6

會發生什麼,如果你的Derived::a_method()嘗試使用僅出現在Derived,而不是在Base數據成員,你怎麼稱呼它一個Base對象(或Base衍生而來,但沒有涉及到Derived對象)嗎?

轉換其他方式是有道理的,這不是。

3

不,它有潛在危險。

派生類函數可以使用所有的*this派生類的屬性。可以在任何基類實例上調用指向基類函數的指針,即使是那些不是派生類型的指針。

訪問未派生類是不會工作,所以鑄件的指針派生類函數的指針基類指針實例的派生類的屬性是否正確不允許的。

在另一方面,鑄造一個指向基類的函數的指針派生類的功能是安全和合法的。

1

您需要使用std::function<void()>。這可以是任何類的任何成員,lambda,自由函數,函數對象,無論您需要什麼,這都非常方便。

#include <iostream> 
#include <typeinfo> 
using namespace std; 
struct Base{ 
    std::function<void()> any_method; 
    void call_it(){ 
     any_method(); 
    } 
}; 
struct Derived: public Base{ 
    void a_method(){ 
     cout<<"method!"<<endl; 
    } 
}; 
int main(){ 
    Derived* d = new Derived; 
    Base& a= *d; 
    a.any_method = [d] { d->a_method(); }; 
    a.call_it(); 
} 

在這裏你可以看到,any_method實際執行是完全抽象struct Base,我可以在清一色提供一個函數對象,做任何事情,包括方便地調用了派生方法。

+1

std :: function可以在這裏幫助:'std :: function '有同樣的問題,如果放棄給any_method成員的類型函數,那麼沒有必要使用'std :: function'而不是普通的空閒函數指針。對? – 2012-04-15 14:40:08

+0

@洛倫佐:號'std :: function '。該函數可以存儲它自己的'this'指針。另外,例如,在函數指針 - 有狀態lambda表達式上總是有'std :: function'指向'std :: bind'的結果。我編輯了我的答案,以使std :: function'能夠立即解決這個問題。 – Puppy 2012-04-15 16:42:29

0

我想這可能有點令人驚訝。不過,如果你仔細想想它是有道理的。

對於兩種類型之間的流延是自動的,下面的關係應持有:所述第一類型的任何實例應該在第二表示的。

例如,如果dDerived一個實例,則它可以自動地轉換爲Base&由於Derived任何實例也是Base一個實例。這是繼承。

現在,當涉及到指針成員函數,關係實際上是顛倒。看起來很明顯,對於Derived的實例存在Base的任何方法,但反過來是不正確的。畢竟所有的推導都是爲了更經常地添加新的功能。

可視化的另一種方法是使用自由函數。 this是在常規功能只是一個隱含參數,如果我們把它明確我們得到:

void [email protected]_it(Base& self); 

void [email protected]_method(Derived& self); 

現在,如果我有兩個實例DeriveddBase類型則b

後者可能是[email protected]_method(dynamic_cast<Derived&>(b)),但是這會引入運行時檢查來實際驗證屬性。靜態它是不可判定的。

相關問題