C++用类封装函数有什么好处么?
天蓬老师
天蓬老师 2017-04-17 11:49:55
0
3
680

看有的代码可以用函数实现,却用类来封装.

具体例子是这样:
比如STL的list容器,sort的函数可以自定义
一般这样处理:

// comparison, not case sensitive.
bool compare_nocase (string first, string second)
{
  unsigned int i=0;
  while ( (i<first.length()) && (i<second.length()) )
  {
    if (tolower(first[i])<tolower(second[i])) return true;
    ++i;
  }
  if (first.length()<second.length()) return true;
  else return false;
}
mylist.sort(compare_nocase);

这个是c++参考手册的例子,项目中我看到好多地方这么用了

    struct mylistSort {
        bool operator() (string first, string second) const {
            //todo
        }
    };
    mylist.sort(mylistSort());

这样有很明显的好处 还是单纯的风格问题,完全等价?

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

reply all(3)
PHPzhong

The ones above are functions, and the ones below are called functors. (I’ll translate it as functors for now)

The most essential difference between the two is that the above is just a process; while the below can contain states. In the latter, closures can be easily implemented.

In C++11, the latter has directly evolved into lambda.


I will use the sort you mentioned to give a small example:

cppbool myfunction (int i,int j) { return (i<j); }

struct myclass {
  bool operator() (int i,int j) { return (i<j);}
} myobject;

std::vector<int> myvector{32,71,12,45,26,80,53,33};

std::sort (myvector.begin(), myvector.end(), myfunction);
std::sort (myvector.begin(), myvector.end(), myobject);

Simplifying your example, let’s focus on the essential differences. It seems to be equivalent, right?

Then the demand has changed now. When sorting, I only want to sort the elements whose value is greater than 40. What should I do? You said, I have to write this 40 into the function. So what if I say this 40 comes from user input? It may also be 50 or 60. What should I do?

At this point, function seems to be a bit useless. But our functor can still be useful.

cppstruct myclass {
    int flag;
    myclass(int i) : flag(i) { }
    bool operator() (int i,int j) { return ((flag < i || flag < j) && i < j);}
};

std::vector<int> myvector{32,71,12,45,26,80,53,33};
myclass myobject(40);
std::sort (myvector.begin(), myvector.end(), myobject);

// output: 32 12 26 33 45 53 71 80

The example may be a little weird. . But do you understand what this means?

左手右手慢动作

This struct is actually a functor, which is translated into functor in China. Its advantage is that it can save state.

Let me give you an example. You are using the function pointer of compare_nocase as a parameter. If suddenly there is another place that requires you to compare strings, but this time you are required to ignore the first letter and start the comparison from the second string, then you What should be done?

1. Either you rewrite a compare_nocase2 function, but it will cause a lot of duplicate code.
2. Either you get an int start variable and put it outside compare_nocase. When executing the requirement I just mentioned, first change start=2, and then change the global variable back after execution.

As you can see, it’s not elegant.
Maybe you thought of writing compare_nocase into a class, but it must be a static method.

The solution to functor is very simple.

cppstruct mylistSort {
  int start;
  mylistSort(int p) { start = p; }
  bool operator() (string first, string second) const {
    int i=start-1;
    while ( (i<first.length()) && (i<second.length()) ) {
      if (tolower(first[i])<tolower(second[i])) return true;
      ++i;
    }
    if (first.length()<second.length()) return true;
    else return false;
  }
};

In this way, you can start the comparison from the first character with mylist.sort(mylistSort(1)); and when you need to ignore the first character and start the comparison with the second letter, you can use mylist.sort(mylistSort(2)) ;

This easily avoids the state management of global variables.

In fact, functor has many other benefits, especially when written with a template, it will play a great role!

By the way, in C++11, you can write it like this

cppmylist.sort([](string first, string second) {
          // 比较逻辑
           });

If you are using C++14, you can also change it to auto~~

伊谢尔伦

This usage of myListSort is called a "function object" or "functor". As can be seen from the name, myListSort is a class (or structure), not a function, but its usage is quite similar to a function, that is, it can be "called" by calling a function. The reason is that it overloads the calling operation. symbol"()".

What are the benefits? Let’s take a classic example (given on C++ Primer): If you want to count how many words in an article are longer than 6, then you definitely need to define a function to determine whether the length of a word is more than 6. This function is as follows:

bool GT6(const string &s) {
  return s.size() >= 6;
}

Then pass the function to count_if to count the number of words with a length of more than 6 in the vector words:

vector<string>::size_type wc = count_if(words.begin(), words.end(), GT6);

This requirement is easy to implement, but the problem is that if 6 is written in the code like above, then there is a new requirement, which is to count the number of words with a length of more than 5, or a word with a length of more than 10 The number of words means that we must reimplement similar functions GT5 and GT10. What if there are more similar needs? Do we need to implement each function one by one?

Using function objects can save us these troubles. Because function objects are class types, they can have their own data members. Define a data member bound, and assign a value to bound when initializing the function object. If you want to count the number of words with a length of more than 5, then bound=5; if it is more than 6, then bound=6, and so on. The specific code is as follows:

class GT_cls {
 public:
  GT_cls(size_t val = 0) : bound(val) { }
  bool operator() (const string &s) {
    return s.size() >= bound;
  }
 private:
  std::string::size_type bound;
};

Now, if you want to count the number of words with a length of more than 5 in words, the code is as follows:

vector<string>::size_type wc = count_if(words.begin(), words.end(), GT_cls(5));

Similarly, if you want to count the number of words with a length of more than 6 in words, the code is as follows:

vector<string>::size_type wc = count_if(words.begin(), words.end(), GT_cls(6));

Obviously, the advantage of using a function object is that it can have data members, making this "functor" more flexible and easier to use.

For another example, let’s say you want to define a nearest neighbor function. What is "recently"? This means we have to define a distance metric. Suppose we are using weighted Euclidean distance as the metric. In C language, the distance metric can be passed into the nearest neighbor function as a function pointer. In C++, we have a more convenient function object! Therefore, we can put the "weight" in the function object as its data member. According to different requirements, initialize the function object with different weights, so that the nearest neighbor function can produce different results!

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!