C++ sort报错:Reference to non-static member function must be called

发布于 / 程序猿 / 0 条评论

最近在做题的时候遇到了这个问题,就是对string字符串直接进行sort排序,自定义排序函数,但是无法通过编译。

问题

对于这个问题,具体的中文意思是:必须调用对非静态成员函数的引用,看着不好懂,我们具体来讲一下。

先看一下报错的代码:

class Solution {
public:
    int cnt[256] = {0};

    bool cmp(char a, char b)
    {
        return cnt[a] > cnt[b] || (cnt[a] == cnt[b] && a < b);
    }

    string frequencySort(string s) {
        int n = s.length();
        memset(cnt, 0, sizeof cnt);
        for (int i = 0; i < n; ++i)
            cnt[s[i]]++;
        sort(s.begin(), s.end(), cmp); // Reference to non-static member function must be called
        return s;
    }
};

为什么会犯这样的错误呢?因为我们平时如果不在类里边写的话是没有问题的,比如下面的代码不会报错:

#include <bits/stdc++.h>
using namespace std;
int cnt[256];

bool cmp(char a, char b) // 全局普通函数
{
    return cnt[a] > cnt[b] || (cnt[a] == cnt[b] && a < b);
}

string frequencySort(string s)
{
    int n = s.length();
    memset(cnt, 0, sizeof(cnt));
    for (int i = 0; i < n; ++i)
        cnt[s[i]]++;
    sort(s.begin(), s.end(), cmp);
    return s;
}

int main()
{
    cout << frequencySort("aacdaddbnsdfik") << endl;
    return 0;
}

所以问题就出在我们自己写的比较函数,下面讲一下怎么解决。

解决

正常情况下来说,只需要在自定义比较函数bool cmp(char a, char b) {}前加一个static使其变成静态成员函数static bool cmp(char a, char b) {}就能解决问题。

但是我写的代码会报一个新的错误Invalid use of member ‘cnt’ in static member function,也就是说cnt变量在静态成员函数中的使用是无效的,当我在cnt前也加上static后再次编译又会产生一个新的bug:undefined reference to Solution::cnt ,这涉及到静态数据成员的初始化问题,就不在这里多讲了。

主要讲一下为什么加一个static就可以解决之前的那个问题。

  • 首先看一下sort函数的原型(带比较函数的这个):
template <class RandomAccessIterator, class Compare>
  void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

// Sorts the elements in the range [first,last) into ascending order.
// Equivalent elements are not guaranteed to keep their original relative order (see stable_sort).
  • 然后再看一下比较函数comp的说明(如下),意思就是说comp函数把排序范围中的两个元素作为参数,返回一个bool类型的值,表明两个元素之间的大小顺序关系,该函数不能修改参数的值,所以最好在参数前加const写成这样bool cmp(const Type1 &a, const Type2 &b);,最后是指这可以是一个函数指针或者函数对象。
Binary function that accepts two elements in the range as arguments, and returns a value convertible to bool. The value returned indicates whether the element passed as first argument is considered to go before the second in the specific strict weak ordering it defines.
The function shall not modify any of its arguments.
This can either be a function pointer or a function object.
  • 但是我们在类里写的比较函数cmp是一个非静态成员函数,而非静态成员函数指针和普通函数指针有区别,所以会报错,加上static后变成静态成员函数,因为静态成员函数指针和普通函数指针没有区别,所以就不会有问题了。详细解释可以参考这篇博客,我摘录一部分。
简单的讲,指向类成员函数的指针与普通函数指针的区别在于,前者不仅要匹配函数的参数类型和个数以及返回值类型,还要匹配该函数指针所属的类类型。
a)参数类型和个数
b)返回值类型
c)所属的类类型(特别之处)
究其原因,是因为非静态的成员函数必须被绑定到一个类的对象或者指针上,才能得到被调用对象的this指针,然后才能调用指针所指的成员函数(我们知道,所有类的对象都有自己数据成员的拷贝,但是成员函数都是共用的,为了区分是谁调用了成员函数,就必须有this指针,this指针是隐式的添加到函数参数列表里去的)。

类的静态成员和普通成员的区别在于,他们是不依赖于具体对象的,所有实例化的对象都共享同一个静态成员,所以静态成员也没有this指针的概念。
所以,指向类的静态成员的指针就是普通的指针。
  • 至此,问题基本解决。实际上sort还有一种“在我看来比较牛逼”的写法,因为我之前没见过。
sort(s.begin(), s.end(), [&](char a, char b) // [&]表示使用了外部变量a/b
{
    return cnt[a] > cnt[b] || (cnt[a] == cnt[b] && a < b);
});

参考

吐槽

话说使用Codeblocks的时候报错一大堆,没法直接定位具体错误,CLion还没有编译的时候就弹出提示了,是真的好使,不愧作为生产力工具。


The end.
2019年2月16日 星期六

转载原创文章请注明,转载自: 太傅 » C++ sort报错:Reference to non-static member function must be called
Not Comment Found