c – 为什么通过引用传递从std :: function派生的对象会导致程序
如果我通过引用将从std :: function派生的对象传递给另一个函数,则程序在运行时始终会因bad_function_call错误而崩溃.如下面的代码所示:
#include<functional> #include<iostream> class foo :public std::function<int(void)> { public: int operator()(){return 1;} }; void bar(const std::function<int(void)>& f) {std::cout << f() << std::endl;} int main(){ foo f; bar(f); } 但是,如果函数对象通过值传递,如下所示: void bar(std::function<int(void)> f) 程序运行正常.我在gcc,clang和visual studio上测试了这个程序,结果是一样的.导致这个bad_function_call的原因是什么? 解决方法
std :: function :: operator()不是虚拟的.
class foo :public std::function<int(void)> { public: int operator()(){return 1;} }; 当将foo视为std :: function时,你编写的operator()什么都不做.你有一个空的std :: function< int()> ;,而不是一个返回1的. std :: function执行基于类型擦除的多态,而不是基于继承的多态.它可以存储任何可以调用,复制和销毁的东西.您可以按值传递它,并且存储的可调用对象将随之传递. 继承它往往不是你想要做的. class foo { public: int operator()(){return 1;} }; 这可以转换为std :: function.实际上,通过此更改,您的代码可以编译并运行. 如果没有这个改变,它更喜欢cast-to-base并将对(空)base std :: function的引用传递给参数.没有继承,它会尝试将foo转换为std :: function并成功. 当然,这个foo非常愚蠢. 而不是这个: int main(){ foo f; bar(f); } 我们做得到: int main(){ auto f = []{ return 1; }; bar(f); } 它的工作原理也一样. (上面的lambda在重要的方面自动生成一个几乎与上面的foo类型相同的类.它也不会从std :: function继承.) C支持多种多态.基于继承的多态性不(容易)允许值类型,并且C在值类型上繁荣,因此编写std :: function以使用值类型. 作为@ T.C.如下所述, void bar(std::function<int(void)> f) 这是有效的,因为编译器在“切片”到基类和使用转换构造函数之间进行选择,并且转换构造函数是C标准的首选. void bar(std::function<int(void)> const& f) 这里不是首选,因为不需要进行转换,只需“将其视为基础”,这比在规则中构造新对象具有更高的优先级. 在我们传递lambda或“unparented”foo的情况下,“引用父类”的情况不可用,所以从我们的foo(或lambda)创建一个临时的std :: function并且f绑定到它. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |