错误信息 “reference to non-static member function must be called” 表示代码尝试将非静态成员函数(在这里是 cmp)当作函数指针使用,但不能这样做,因为非静态成员函数需要一个对象才能被调用。
解决这个问题的方式是将 cmp 函数声明为 static。
即cmp的函数定义,应该写成:
static bool static cmp(const pair<int,int>&a,const pair<int,int>&b){
return a.second<b.second;//降序排列
}
本题中,cmp函数必须声明为static是因为它是作为类的成员函数使用的。
成员函数默认是与类的实例相关联的,需要通过实例来调用。然而,在使用sort函数时,我们需要传递一个函数指针或函数对象作为比较函数,而成员函数无法直接转换为函数指针。
因此,为了让成员函数能够作为比较函数传递给sort,我们需要将其声明为static,这样它就不再与类的实例相关联。
静态成员函数不需要对象就能被调用,因此可以被用作函数指针。
但是,静态成员函数不能访问类的非静态成员(包括数据和函数),但在本题例子中,cmp 并没有访问其他非静态成员,所以将它声明为 static 不会有问题。
报错代码:
class Solution {
public:
//遍历整棵树,用map统计频率
//这里的遍历顺序不重要,只要全部遍历了就行
unordered_map<int,int>map;
vector<int>result;
void searchTree(TreeNode* root){
if(root==nullptr){
return;
}
//此处用了前序
map[root->val]++; //统计元素频率
searchTree(root->left);
searchTree(root->right);
}
//把统计出来的value进行排序,注意map不能直接对value排序
//因为map中的数据类型是pair,因此sort的cmp需要重新定义降序排列
bool cmp(pair<int,int>& a,pair<int,int>& b){
//注意键值对的pair类型并不是指针,不能用->来访问
if(a.second>b.second){
return true;
}
else
return false;
}
vector<int> findMode(TreeNode* root) {
//把map里的数据存在数组里
vector<pair<int,int>>vec(map.begin(),map.end());
//对数组里的pair.second进行排序
sort(vec.begin(),vec.end(),cmp);
//取最高value的元素key,此时数组vec中已经是value降序排好序的
result.push_back(vec[0].first);
//把vec中最高value元素存进result里
for(int i=1;i<vec.size();i++){
if(vec[i].second == vec[0].second){
result.push_back(vec[i].first);
}
}
return result;
}
};
修改结果:
class Solution {
public:
//遍历整棵树,用map统计频率
//这里的遍历顺序不重要,只要全部遍历了就行
unordered_map<int,int>map;
vector<int>result;
void searchTree(TreeNode* root){
if(root==nullptr){
return;
}
//此处用了前序
map[root->val]++; //统计元素频率
searchTree(root->left);
searchTree(root->right);
}
//把统计出来的value进行排序,注意map不能直接对value排序
//因为map中的数据类型是pair,因此sort的cmp需要重新定义降序排列
bool static cmp(pair<int,int>& a,pair<int,int>& b){
//注意键值对的pair类型并不是指针,不能用->来访问
if(a.second>b.second){
return true;
}
else
return false;
}
vector<int> findMode(TreeNode* root) {
//把map里的数据存在数组里
vector<pair<int,int>>vec(map.begin(),map.end());
//对数组里的pair.second进行排序
sort(vec.begin(),vec.end(),cmp);
//取最高value的元素key,此时数组vec中已经是value降序排好序的
result.push_back(vec[0].first);
//把vec中最高value元素存进result里
for(int i=1;i<vec.size();i++){
if(vec[i].second == vec[0].second){
result.push_back(vec[i].first);
}
}
return result;
}
};
如果是在类里作为成员函数定义了cmp,那么这个cmp就需要依赖函数实例才能使用。非静态成员函数不能直接作为普通函数指针来传入sort中。
在C++中,非静态成员函数需要一个对象(即隐式的 “this” 指针)来进行调用,因此不能直接作为普通函数指针来使用,否则编译器不知道用哪个对象来调用该成员函数。这就是你在尝试将 cmp 作为参数传递给 sort 函数时发生错误的原因。
另一方面,静态成员函数不依赖于任何对象,因此可以被直接调用,不需要创建对象,就像普通的全局函数一样。因此,静态成员函数可以被直接用作函数指针,也可以作为其他函数的参数。
如果想将成员函数作为参数传递给 sort 函数,需要将这个成员函数声明为 static。但这只适用于那些不需要访问对象状态(即对象的非静态数据成员)的函数,因为静态成员函数不能访问非静态数据成员。如果你的比较函数需要访问对象状态,你可能需要使用其他方法,如使用函数对象(functor)或lambda表达式。
当我们将比较函数声明为静态成员函数时,它不能直接访问类中的非静态成员变量,也不能访问其他函数体内部的局部变量。静态成员函数只能访问静态成员变量和其他静态成员函数。
因此**,如果比较函数cmp需要访问对象的状态或其他非静态数据**,需要使用函数对象(functor)或 lambda 表达式。
函数对象可以持有对象的状态作为成员变量,并在函数调用运算符 operator() 中访问这些状态。
而 lambda 表达式可以捕获外部变量,并在函数体中访问这些捕获的变量。
这些方法允许在比较函数中访问对象的状态或其他局部变量,并将其作为参数传递给 sort 函数。因此,当需要访问对象状态或其他局部变量时,使用函数对象或 lambda 表达式是更好的选择。
如果 cmp 函数需要访问对象状态,不能将其声明为静态成员函数,我们可以考虑使用函数对象(functor)或 lambda 表达式来实现。
函数对象(functor): 函数对象是一个类对象,它重载了函数调用运算符 operator()。通过在类中定义一个函数调用运算符重载函数,可以实现具有状态的比较函数。
struct Cmp {
int state;
Cmp(int s) : state(s) {}
bool operator()(const pair<int, int>& a, const pair<int, int>& b) {
// 可以访问对象的状态
if (a.second > b.second + state) {
return true;
} else {
return false;
}
}
};
// 使用函数对象进行排序
Cmp cmpObject(10);
sort(vec.begin(), vec.end(), cmpObject);
Lambda 表达式: Lambda 表达式是一种匿名函数的方式,可以在函数中直接定义比较函数,并捕获外部的对象状态。
int state = 10;
// 使用 lambda 表达式进行排序
sort(vec.begin(), vec.end(), [state](const pair<int, int>& a, const pair<int, int>& b) {
// 可以访问外部对象的状态
if (a.second > b.second + state) {
return true;
} else {
return false;
}
});
在上述示例中,函数对象 Cmp 或 lambda 表达式都可以访问外部对象的状态,并将其作为比较函数传递给 sort 函数。这样就可以根据需要在比较函数中访问对象状态,并根据状态进行排序。
如果cmp函数是作为普通的自由函数声明的,而不是类的成员函数,那么就不需要声明为static。
自由函数不依赖于任何特定的类实例,因此可以直接传递给sort函数作为函数指针。
例子:
struct Student {
string name;
int score;
};
bool cmp(const Student& a, const Student& b) {
return a.score < b.score;
}
vector<Student> students;
// fill students...
sort(students.begin(), students.end(), cmp);