C++函数指针强制转换
C++ function pointer casting
我现在正在为数据结构类开发一个模板化的二叉搜索树,C++。到目前为止,一切都很顺利。这个问题涉及一些我不熟悉的C++细节,我需要帮助。
我之前已经定义了遍历树并以不同顺序访问每个节点的函数。这里所讨论的那个定义如下。
TreeNode.h
public:
static void PostOrderVisit(TreeNode<T>* node, void visit(const T& v));
树节点.cpp
template <class T> void TreeNode<T>::PostOrderVisit(TreeNode* node, void visit(const T& v)) {
if (node->leftChild != NULL)
PostOrderVisit(node->leftChild, visit);
if (node->rightChild != NULL)
PostOrderVisit(node->rightChild, visit);
visit(node->value);
}
这在创建节点并静态调用PostOrderVisit的测试程序中工作正常。
在一个友元类(BinSTree.h/cpp)中,我正在实现一个删除树中每个节点的方法,所以我认为使用这个访问者并在每个节点上调用我的Delete()函数是个好主意(Delete()函数在BinSTree的测试程序中也可以正常工作)。
此函数定义如下。
template <class T> void BinSTree<T>::ClearTree() {
TreeNode<T>::PostOrderVisit(this->root(), &BinSTree<T>::Delete);
}
问题就在这里。 g++ 说...
BinSTree.cpp:156: error: no matching function for call to ‘TreeNode<int>::PostOrderVisit(TreeNode<int>*, void (BinSTree<int>::*)(const int&))’
TreeNode.cpp:56: note: candidates are: static void TreeNode<T>::PostOrderVisit(TreeNode<T>*, void (*)(const T&)) [with T = int]
在这种情况下,我认为void (BinSTree<T>::*)(const T&)
会是void (*)(const T&)
的实例,但事实并非如此。我可以让函数定义识别调用的唯一方法是像这样强制转换函数指针:
TreeNode<T>::PostOrderVisit(this->root(), (void (*)(const T& v)) &BinSTree<T>::Delete);
这识别函数并适当地调用它,但是(这需要一些重要的研究......),C++成员函数有一个隐式参数,允许从内部访问"this"关键字。将成员函数指针强制转换为普通函数指针会完全删除"this"引用,导致我的 Delete() 方法出现错误(它经常使用"this")。
这一直很麻烦,我在这个项目的这么小的一点点上花了相当多的时间。谁能告诉我一种方法,要么 A:在没有强制转换的情况下识别函数,要么 B:如何在整个转换中保持"this"引用。ClearTree() 和 Delete() 方法都在同一个类中。
提前谢谢。
首先,PostOrderVisit
应该将函数参数作为指针,即 PostOrderVisit(TreeNode<T>* node, void (*visit)(const T& v))
.
但是,这不会解决您的问题,因为您正在向其传递非静态成员函数。要么你传递给它的函数必须在类中static
,要么你可以使用类似std::function
的东西而不是函数指针参数,即 PostOrderVisit(TreeNode<T>* node, std::function<void(const T&)> visit)
.
编辑在这种情况下,我认为您有两种方法可以做到这一点:一种是更改设计以适应参数,这意味着您不能使用成员方法作为参数。第二种是更改代码以适应您的设计,并向老师解释由于界面的限制而必须更改界面,并解释这些限制。
使用普通函数指针作为参数的问题在于,成员函数对于类的实例具有隐式和隐藏参数 this
。 普通函数没有此隐藏参数,因此编译器禁止您使用成员函数。解决方案是使用普通函数,这不是很C++,另一种是使用static
成员函数(因为它们没有this
指针),或者使用类似 std::function
的东西。
至于如何使用std::function
,你在PostOrderVisit
的声明和定义中使用它,就像我所展示的那样。当你调用它时,你会做这样的事情:
template <class T> void BinSTree<T>::ClearTree() {
TreeNode<T>::PostOrderVisit(this->root(), std::mem_fn(&BinSTree<T>::Delete));
}
非静态方法采用"this"的隐式参数。 例如,对于方法 C::f(int i),您可以将其视为 f(C* this, int i)。你所做的任何铸造并搞砸了这个签名,你都可以预料到坏事会发生。您已经经历过崩溃,但更险恶的伪影可能会使程序在其他看似随机的地方行为不正常或崩溃。
您可以使用指向成员函数的指针,如下所示:
在 .h 中
template <class C>
static void PostOrderVisit(C* node, void (C::* visit)(const T& v));
在 .cpp 中(实际上如果它是一个模板,它必须全部在 H 中,否则链接错误)
template <class T>
template <class C>
void TreeNode<T>::PostOrderVisit(C* node, void (C::* visit)(const T& v))
{
// ...
T value;
(node->*visit)(value);
// ...
}
您可以传递指向派生类的指针(此处所示的 C),也可以传递指向基类的指针(原始中的 TreeNode)。在某些时候,您可能需要投射。
您也可以在以访客身份传递普通函数时保留原始函数。函数重载会小心。
更通用的方法是使用 std::function。虽然它可能有一些轻微的性能影响,但它是最通用的。
例如(未编译可能有一些小的语法错误):
static void PostOrderVisit(TreeNode<T>* node, std::function<void (const T& v)> visit);
在PostOrderVisit中,您只需执行访问(值),例如像正常功能一样调用。
当您调用PostOrderVisit时,您可以使用std::bind或boost::bound的所有功能来携带尽可能多的额外信息。 例如
PostOrderVisit(this->root(), std::bind(&BinSTree::D elete, this));
- 转换指针引用的字符串
- 无法向上转换指针到指针参数
- 混合转换指针和引用
- 堆栈对象的强制转换指针
- 基类到派生模板类的强制转换指针,而不知道类型
- 删除类型转换指针的最佳方法
- 管理到本机值类转换:强制转换指针是否安全?
- 转换指针类型
- 为什么函数不能正确强制转换指针(从基类到派生类)
- 当我们递增下面的类型转换指针时会发生什么?
- 类型强制转换指针构造函数调用
- 如何转换(指针向量)-->(指向指针数组的指针)
- 如何从类功能转换指针
- 在C++对象中:我应该使用父类强制转换指针,还是应该使用实际类本身进行强制转换
- Delphi中的类型转换指针添加
- C++分段错误(核心转储)错误 - 强制转换指针/将函数值返回到线程
- 以C++和运算符优先级键入指向数组成员的强制转换指针
- C++动态强制转换指针的内存清理
- 转换指针和引用的好处
- 在c++中转换指针