C++成员函数指针赋值报错:非静态成员函数引用必须被调用
非静态成员函数的调用约定和普通函数、静态成员函数完全不同:每个非静态成员函数都会隐式携带一个指向当前类实例的this指针作为入参,因此它的函数类型和你声明的普通函数指针void (*download_func)(std::string)不匹配。
代码中直接写downloadVideo/downloadAudio时,编译器会判定你试图在未绑定实例、未传入参数的情况下引用成员函数,因此抛出"Reference to non static member function must be called"错误。
将两个方法改为静态函数能通过编译,本质是因为静态成员函数没有隐式this参数,函数签名和普通函数指针匹配,但这种方案确实会导致函数无法访问实例的私有成员,不符合需求。
方案1:使用原生C++成员函数指针
这是无额外依赖的标准写法,只需要修正函数指针的类型、赋值和调用语法即可,修改后的download()实现如下:void Downloader::download(){ std::ifstream url_list; // 声明匹配Downloader类非静态成员函数的指针类型 void (Downloader::*download_func)(std::string) = video_or_audio == 0 ? &Downloader::downloadVideo : &Downloader::downloadAudio; if(video_or_audio == 0){ url_list.open("video_list.txt"); } else { url_list.open("audio_list.txt"); } std::string url; while(std::getline(url_list, url)){ // 成员函数指针必须绑定当前实例this才能调用,注意括号不能省略 (this->*download_func)(url); } }注意点:给成员函数指针赋值时必须显式加取地址符
&,同时添加类名限定Downloader::;调用时要使用->*(通过实例指针调用)或.*(通过实例/引用调用)运算符,必须给整个调用表达式加括号,避免运算符优先级导致语法错误。方案2:使用std::function包装可调用对象
如果觉得原生成员函数指针语法晦涩难记,可以使用C++标准库提供的std::function,提前绑定当前实例的this指针,后续调用逻辑和普通函数完全一致。使用前需要引入头文件<functional>,核心修改代码如下:#include <functional> #include <fstream> #include <string> void Downloader::download(){ std::ifstream url_list; std::function<void(std::string)> download_func; if(video_or_audio == 0){ download_func = [this](std::string url){ this->downloadVideo(url); }; url_list.open("video_list.txt"); } else { download_func = [this](std::string url){ this->downloadAudio(url); }; url_list.open("audio_list.txt"); } std::string url; while(std::getline(url_list, url)){ download_func(url); } }这种写法可读性更强,后续如果需要扩展调用逻辑、修改参数传递规则也更灵活。
内容的提问来源于stack exchange,提问作者Gabriel

