2013-03-29 44 views
3

我們有一個常用的類層次結構:爲什麼函數指針會破壞替代性,而std :: function不會呢?

class B 
{ 
public: 
    int x; 
    B() : x(0) {} 
    virtual ~B() {} 
}; 

class D : public B 
{ 
public: 
    int y; 
    D() : y(0) {} 
}; 

而這需要一個參數的函數 - 參照基類對象。

void b_set(B& b) 
{ 
    b.x = 5; 
} 

然後,我想創建void (D&)類型的函數指針和存儲b_set在裏面。這應該是有效的操作,因爲合法傳遞給函數指針調用的所有對象也必須是B類型的,但它是不允許的。

typedef void (*fp_d_mutator)(D&); 
void fp_test(D& obj) 
{ 
    fp_d_mutator fun = b_set; //invalid conversion from 'void (*)(B&)' to 'fp_d_mutator {aka void (*)(D&)} 
    fun(obj); 
} 

#include <functional> 
typedef std::function<void (D&)> stdfun_d_mutator; 
void stdfun_test(D& obj) 
{ 
    stdfun_d_mutator fun = b_set; //works 
    fun(obj); 
} 

所以......

  • 如何是無效的轉換?
  • 爲什麼是無效轉換?
  • 如果允許,會發生什麼情況?
  • std :: function如何避免第一個問題?
+0

其編譯器和版本沒有的 「作品」 適用於 –

+0

@ Cheersandhth. - 阿爾夫G ++ 4.7.2的MinGW – milleniumbug

+0

HM,thinko,SRY –

回答

3

這需要B&類型的參數的函數不是一個函數,它D&類型的參數。雖然D&可轉換爲B&,它們不是相同的類型。如果您可以存儲指向函數的指針,該函數需要B&作爲指向D&的指針,那麼編譯器將如何知道何時轉換參數? (請注意,轉換有時需要調整一個指針)

std::function不同的是,主叫簽名(這裏D&)是函數對象的類型,被叫簽名(這裏B&)的一部分是部分內部存儲器。因此,當您應用函數對象operator()時,實現operator()(D&)的代碼負責轉換。

+0

哦,對了,忘了指針調整。因此,除了調用存儲函數之外,std :: function還會調用必要的轉換。是的,答案是令人滿意的,但我會稍等片刻才能接受。 – milleniumbug

+0

@milleniumbug - 是的,差不多。函數調用運算符不會明確地進行任何轉換;當可調用對象(在這種情況下是指向函數的指針)被存儲到'std :: function'對象中時,賦值運算符也存儲了類型信息。調用可調用對象就像調用「普通」函數一樣:void f(float); int i; F(1);'。沒有明確的轉換,但編譯器根據需要調整類型。 –

相關問題