为什么函数指针破坏了可替代性而std :: function却没有?

时间:2013-03-29 18:10:05

标签: c++ function-pointers liskov-substitution-principle

我们有一个通常的类层次结构:

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如何首先避免这个问题?

1 个答案:

答案 0 :(得分:3)

采用类型B&的参数的函数不是采用类型D&的参数的函数。虽然D& 可转换为 B&,但它们的类型不同。如果你可以存储一个指向函数的指针,该函数将B&作为D&的指针,那么编译器如何知道何时转换参数? (注意转换有时需要调整指针)

std::function的区别在于调用签名(此处为D&)是函数对象类型的一部分,是被调用签名(此处为B& )是内部存储的一部分。因此,当您应用函数对象“operator()时,实现operator()(D&)的代码将负责转换。