讓我們假設你的類層次結構是有點大:
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
,你擁有的功能像下面:
void takeA(A* ptr)
{
ptr->a = 1;
}
void takeB(B* ptr)
{
ptr->b = 2;
}
有了這樣的,我們可以說,takeA
是調用任何實例類派生自A
(或A
本身),並且該takeB
是可調用與任何實例的cl屁股B
:
takeA(new A);
takeA(new B);
takeA(new C);
takeB(new B);
// takeB(new A); // error! can't convert from A* to B*
// takeB(new C); // error! can't convert from C* to B*
現在,std::function
是,它是一個包裝可贖回對象。它不那麼在意存儲函數對象的簽名,只要該對象是調用其std::function
包裝參數:
std::function<void(A*)> a; // can store anything that is callable with A*
std::function<void(B*)> b; // can store anything that is callable with B*
你所要做的,就是std::function<void(B*)>
轉換爲std::function<void(A*)>
。換句話說,您想要將包含B*
的可調用對象存儲在包裝類中,其功能爲A*
。是否存在A*
到B*
的隱式轉換?不,那裏沒有。
也就是說,一個可以作爲很好的指針調用std::function<void(A*)>
到C
類的一個實例:
std::function<void(A*)> a = &takeA;
a(new C); // valid! C* is forwarded to takeA, takeA is callable with C*
如果std::function<void(A*)>
可以包裝調用對象的實例只B*
服用,你將如何指望它與C*
一起工作?:
std::function<void(B*)> b = &takeB;
std::function<void(A*)> a = b;
a(new C); // ooops, takeB tries to access ptr->b field, that C class doesn't have!
幸運的是,上面的代碼沒有編譯。
然而,這種反其道而行之的方式是罰款:
std::function<void(A*)> a = &takeA;
std::function<void(B*)> b = a;
b(new B); // ok, interface is narrowed to B*, but takeA is still callable with B*
可能重複[C++模板多態](http://stackoverflow.com/questions/2203388/c-templates-polymorphism) – Samuel 2014-10-16 11:50:16
它不重複,'std :: function'支持這種*轉換*。但換句話說,您可以將'std :: function'轉換爲'std :: function ',因爲在'A *'上運行的函數在接收到'B *'的實例時可以做同樣的事情,但是而不是其他方式 –
2014-10-16 11:51:20
問題的根源在於使用'std :: function'作爲回調函數,而不是接受'Functor'作爲模板參數。除非你有充分的理由這樣做,否則不要這樣做。 – pmr 2014-10-16 17:28:55