C++类中存储带参数的void函数指针回调报错求助
C++链表排序实现中的函数指针问题
问题背景
- 正在实现不借助外部数据结构的链表排序算法,逻辑为:先找到最小值移至表头,再排序剩余元素;不使用STL以夯实语言基础
- 计划用
iterate作为遍历主函数,通过函数指针调用print(打印节点值)、getLast(定位尾节点)、findMin(查找最小值)等成员函数 - 选择函数指针而非
std::function或lambda,但遇到编译错误
报错代码片段
void List::iterate(Node * node,void(*callBack)(Node* node)){ callBack(node); if(node->next == nullptr) return; iterate(node->next,callBack); } void List::add(int data){ void (*callback)(Node* node) = &print(root); // 编译错误:Can't take the address of an rvalue of type void iterate(root, callBack); }
错误提示:无法获取void类型右值的地址
完整代码
/* Implement sorting in a dynamic linked list without using an additional array or data structure.*/ #include <iostream> class List{ struct Node{ int data; Node* next = nullptr; }; public: List(int data); ~List(); void add(int data); void iterate(Node * node, void(*callback)(Node* node)); private: void print(Node *node); void findMin(Node* node); void getLast(Node* node); int min = 0; Node* root = new Node; Node* it; }; List::List(int data){ root->data = data; it = root; } List::~List(){} void List::print(Node *node){ std::cout<<node->data<<'\n'; } void List::findMin(Node* node){ if (node->data<min) { min = node->data; } } void List::getLast(Node* node){ it = node; } void List::iterate(Node * node,void(*callBack)(Node* node)){ callBack(node); if(node->next == nullptr) return; iterate(node->next,callBack); } void List::add(int data){ void (*callback)(Node* node) = &print(root); //Can't take the address of an rvalue of type void iterate(root, callBack); } int main(){ List list(8); list.add(9); list.add(7); list.add(4); list.add(3); return 0; }
疑问点
- void返回值的函数在函数指针处理上是否有特殊要求?是否因返回值内存大小导致差异?
- 代码中的错误具体是什么?缺失哪些核心概念?
- 非静态成员函数、lambda、
std::function在类中的适配方法
问题分析与解决
核心错误点
- 函数地址获取逻辑错误:
&print(root)是调用print函数后取返回值的地址,但print返回void,无返回值,属于无效操作。正确做法是取函数本身的地址,而非调用后的结果。 - 非静态成员函数的指针特性:类的非静态成员函数隐含一个
this指针参数,其函数指针类型为void (List::*)(Node*),而非普通的void(*)(Node*),普通函数指针无法直接存储非静态成员函数地址。
解决思路
方案1:改为静态成员函数
若成员函数无需访问类的非静态成员(如print仅打印节点数据),可改为静态:
class List{ // ... private: static void print(Node *node); // 声明为静态 // ... }; // 调用时直接取函数地址 void List::add(int data){ void (*callback)(Node* node) = &List::print; iterate(root, callback); }
方案2:使用std::function+lambda
若需保留非静态成员函数(如findMin需访问min成员),可修改iterate接受std::function,配合lambda捕获this:
#include <functional> // 需包含头文件 // 修改iterate参数类型 void List::iterate(Node * node, std::function<void(Node*)> callback){ callback(node); if(node->next == nullptr) return; iterate(node->next, callback); } // 在add中使用lambda void List::add(int data){ iterate(root, [this](Node* node){ this->print(node); }); }
方案3:使用成员函数指针
若坚持用函数指针,需使用成员函数指针类型,并通过this调用:
// 修改iterate的参数为成员函数指针 void List::iterate(Node * node, void (List::*callback)(Node*)){ (this->*callback)(node); // 通过this调用成员函数 if(node->next == nullptr) return; iterate(node->next, callback); } // 调用时传递成员函数地址 void List::add(int data){ iterate(root, &List::print); }
额外代码反馈
- 析构函数未释放内存:当前
~List()为空,会导致链表节点内存泄漏,需遍历链表释放所有Node。 add函数逻辑错误:当前add未实现添加节点的功能,而是调用了打印,正确逻辑应为:
void List::add(int data){ // 先定位尾节点 it = root; iterate(root, &List::getLast); // 添加新节点 it->next = new Node; it->next->data = data; }
findMin初始化问题:min初始化为0,若链表所有元素均大于0,会导致最小值判断错误,应在遍历前将min初始化为第一个节点的data。
进展说明
正在研究相关代码原理,后续会发布完整解决方案;已按照建议在类声明中用new Node初始化root。
内容的提问来源于stack exchange,提问作者wavesinaroom
相关产品推荐
相关产品推荐

