我有两个课程:Child
来自Parent
:
#include <stdint.h>
#include <iostream>
using namespace std;
class Parent
{
public:
int parentMember;
};
class Child : public Parent
{
};
现在,我有一个用于自定义实现动态数组的类模板(跳过不必要的部分)
template <typename T>
class DArray
{
private:
T* m_array;
int32_t m_length;
public:
// Default constructor
DArray() : m_array{ nullptr }, m_length{ 0 } {
};
// Search returns index of the first found item or -1 if not found, comparison is done
// using function pointer, which should return boolean
int32_t Search(const T& data, bool(*comparisonFunction)(T, T)) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
};
我有一个比较函数,用于查明我的动态数组是否已包含具有相同值parentMember
的元素
bool comparisonFunction(Parent* n1, Parent* n2) {
return (n1->parentMember == n2->parentMember);
}
最后,我有我的动态数组,它应该保存指向Child
个对象的指针。
int main()
{
DArray<Child*> dArray;
Child *c;
dArray.Search(c, comparisonFunction);
return 0;
}
此代码在此行返回错误:
dArray.Search(c, comparisonFunction);
错误是:
argument of type "bool (*)(Parent *n1, Parent *n2)" is incompatible with
parameter of type "bool (*)(Child *, Child *)"
我的问题是:为什么编译器不会隐式地将Child*
转换为Parent*
,因为当我将Child*
作为参数传递给一个带{{1}的函数时作为参数?
如果没有为每个子类实现新的比较函数,有没有办法解决这个问题?
答案 0 :(得分:3)
指针与函数类型之间没有隐式转换。
我会将Search
函数更改为模板函数,该函数可以采用任何函子类型(包括lambdas,std::function
等)。
template <typename F>
int32_t Search(const T& data, const F& comparisonFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
答案 1 :(得分:2)
从Child *
到Parent *
的隐式转换不一定是无操作。它可能涉及指针运算甚至条件(用于检查null)。因此,虽然可以调用一个函数,期望Parent *
的参数类型为Child *
,但这是唯一可能的,因为编译器会在调用点插入任何必要的转换代码。
这意味着虽然您可以将Child *
转换为Parent *
,但您无法直接将 Child *
视为Parent *
。但是,您的算法使用指向类型bool(Child*, Child*)
的函数的指针。因此它会将两个Child *
个对象传递给该函数。在通过函数指针调用的站点,编译器无法知道指针实际指向bool(Parent *, Parent*)
,因此它应该将转换代码从Child *
插入到Parent *
对于每个论点。
在传递指针的站点上也不能插入这样的代码。编译器实际上必须合成类型为bool(Child *, Child *)
的包装器,将转换代码放入其中,并将指向该包装器的指针传递给Search
。对于单个隐式转换而言,这将有点过于昂贵。
其他答案已经给出了问题的正确解决方案:从标准<algorithm>
标题中获取灵感并接受任意仿函数而不是函数指针:
template <class F>
int32_t Search(const T& data, F comparisonFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (comparisonFunction(m_array[i], data))
return i;
}
return -1;
}
答案 2 :(得分:0)
编译器不会这样做。
通常最好将仿函数作为模板参数提交,以便它可以与可以在该位置编译的任何项一起使用。例如,std :: function和捕获lambda将使用模板参数,但不能使用显式函数指针声明。
template <typename T>
class DArray
{
private:
T* m_array;
int32_t m_length;
public:
// Default constructor
DArray() : m_array{ nullptr }, m_length{ 0 } {
};
// Search returns index of the first found item or -1 if not found, comparison is done
// using function pointer, which should return boolean
template<typename COMPARE>
int32_t Search(const T& data,COMPARE& compareFunction) {
for (int32_t i = 0; i < m_length; i++) {
if (compareFunction(m_array[i], data))
return i;
}
return -1;
}
};