2016-11-22 86 views
3

我有2类:ChildParent导出:C++函数指针中的隐式类型转换?

#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*作为参数传递给一个函数时,它会将Parent*作为参数吗?

有什么办法如何解决这个问题,而不是为每个孩子类实现一个新的比较函数?

+0

你不使用'任何理由std :: vector'和''? –

+0

@appleapple我还在学习C++,我想了解它是如何工作的“幕后”:) – Riko

+1

可能最好先了解如何正确地做到这一点。 –

回答

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; 
    } 
}; 
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; 
} 
2

Child *Parent *的隐式转换不一定是无操作。它可能涉及指针算术和条件(用于检查null)。因此,尽管可以调用函数期望带有Child *类型参数的Parent *,但这是唯一可能的,因为编译器会在调用点插入任何必需的转换代码。

这意味着,虽然您可以转换一个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; 
} 
+0

谢谢您的详细解释,我标记了第一个正确答案。 – Riko