Giả sử rằng hệ thống cấp bậc lớp học của bạn là lớn hơn một chút:
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
và bạn có chức năng như dưới đây:
void takeA(A* ptr)
{
ptr->a = 1;
}
void takeB(B* ptr)
{
ptr->b = 2;
}
Có đó, chúng tôi có thể nói rằng takeA
là callable với bất kỳ ví dụ của lớp bắt nguồn từ A
(hoặc A
chính nó) và rằng takeB
là có thể gọi với bất kỳ thể hiện nào của cl ass 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*
Bây giờ, std::function
là gì, nó là một wrapper cho callable đối tượng. Nó không quan tâm nhiều về chữ ký của lưu trữ đối tượng hàm càng lâu càng rằng đối tượng là callable với các thông số của std::function
wrapper của nó:
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*
gì bạn đang cố gắng để làm, là để chuyển đổi std::function<void(B*)>
để std::function<void(A*)>
. Nói cách khác, bạn muốn lưu trữ đối tượng có thể gọi lấy B*
trong lớp trình bao bọc cho các hàm lấy A*
. Có chuyển đổi tiềm ẩn của A*
đến B*
không? Không có.
Đó là, một cũng có thể gọi std::function<void(A*)>
với một con trỏ đến một thể hiện của lớp C
:
std::function<void(A*)> a = &takeA;
a(new C); // valid! C* is forwarded to takeA, takeA is callable with C*
Nếu std::function<void(A*)>
thể quấn một thể hiện của đối tượng callable chỉ B*
uống, làm thế nào bạn mong chờ nó để làm việc với 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!
May mắn thay, mã trên không biên dịch.
Tuy nhiên, làm điều này theo cách ngược lại là tốt:
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ó thể trùng lặp của [Đa hình mẫu C++] (http://stackoverflow.com/questions/2203388/c-templates-polymorphism) – Samuel
không trùng lặp, 'std :: function' hỗ trợ * chuyển đổi * đó. nhưng theo cách khác, bạn có thể chuyển đổi 'std :: function' thành 'std :: function ', bởi vì hàm hoạt động trên 'A *' có thể làm tương tự khi nó nhận một thể hiện của 'B *', nhưng không phải cách khác –
Nguồn của vấn đề của bạn đang sử dụng 'std :: function' như một cuộc gọi lại thay vì chấp nhận một' Functor' làm đối số mẫu. Trừ khi bạn có một lý do chính đáng để làm điều này, đừng làm điều đó. – pmr