You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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在类中的适配方法

问题分析与解决

核心错误点

  1. 函数地址获取逻辑错误:&print(root)是调用print函数后取返回值的地址,但print返回void,无返回值,属于无效操作。正确做法是取函数本身的地址,而非调用后的结果。
  2. 非静态成员函数的指针特性:类的非静态成员函数隐含一个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);
}

额外代码反馈

  1. 析构函数未释放内存:当前~List()为空,会导致链表节点内存泄漏,需遍历链表释放所有Node。
  2. add函数逻辑错误:当前add未实现添加节点的功能,而是调用了打印,正确逻辑应为:
void List::add(int data){
  // 先定位尾节点
  it = root;
  iterate(root, &List::getLast);
  // 添加新节点
  it->next = new Node;
  it->next->data = data;
}
  1. findMin初始化问题:min初始化为0,若链表所有元素均大于0,会导致最小值判断错误,应在遍历前将min初始化为第一个节点的data。

进展说明

正在研究相关代码原理,后续会发布完整解决方案;已按照建议在类声明中用new Node初始化root。

内容的提问来源于stack exchange,提问作者wavesinaroom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 01:37:49