理解operator()重载

时间:2014-09-11 20:16:46

标签: c++ operator-overloading

我正在尝试了解重载方法,特别是关于bool operator()。 请尝试理解。我确实试过阅读一些关于重载运算符的文章,但仍然无法得到它; /

我有来自STL的set容器,它按字母顺序自动对其''对象'进行排序,但是我想修改它以便它根据它们的长度对字符串进行排序。

这是我难以理解的工作代码

#include <iostream>
#include <set> 
#include <iterator>

using namespace std; 

struct MyOrder
{
   bool operator()(const string &first, const string &second) 
   { 
      int length1 = first.length(); //** assigning length of strings (arguments)
                                    //** to int, so that we will compare their lengths

      int length2 = second.length(); //** same story**//

      if(length1 == length2) //** if both strings are the same length, code will return  
                             //** true, but what does is mean first < second ?, will it 
                                  swap places of arguments or what ? 
         return (first < second); 

      return (length1 < length2); //** same story, if they are not the same length, than    
                                  //** what ? return true, and swap arguments' places ? 
    } 
  } 

int main(void) 
{
   set<string, Myorder> names; 

   names.insert("Tony Soprano"); 
   names.insert("Christopher Moltisanti"); 

   set<string>::iterator it; 

   for(it = names.begin(); it != names.end(); ++it) 
   { 
      cout << *it << endl; 
   } 
 } 

4 个答案:

答案 0 :(得分:1)

set<>的第二个模板参数(如果提供)是一个运算符,用于确定您希望元素的排序方式。默认运算符是使用std::less<>的结果,如果第一个参数小于第二个参数,则返回true。使用默认比较运算符时,将对组中的元素 e 0 .. e N 进行排序,以便 e i &lt; e i + 1 为真。

()的运算符重载允许调用MyOrder的实例,就好像它是一个函数一样。通过提供MyOrder作为第二个模板参数,您要更改集合中元素的顺序,以便orderMyOrder的实例,order( < em> e i e i + 1 )为真。

MyOrder的实施方式如下:

  • 如果两个参数的长度相等,则返回first < second的结果 - 这意味着如果字符串长度相等,如果第一个字符串按字母顺序小于第二个字符串则返回true,否则返回false。

  • 如果两个参数的长度不相等,则first短于second时返回true,否则返回false。

set<>如何维护元素的排序是一个实现细节,但是在添加新元素时它会这样做。最初,当没有元素时,添加第一个元素没有限制。在添加每个新元素时,添加它就好像已使用提供的运算符与所有现有元素进行比较,以确定其正确的相对位置。

因此,如果该集合包含{ "m", "zz", "aaa" },并且您想要向其添加"ii",那么它将放在"m"之后(因为它比它长),但在{{{}之前1}}(因为它按字母顺序小于它)。结果将变为"zz"

答案 1 :(得分:1)

<运算符表示小于,它的计算结果为truefalse。例如:

3 < 4    // true
6 < 5    // false
7 < 7    // false

它不会“交换参数”或任何东西。

当应用于std::string等类类型时,<等运算符会调用该类的重载operator<函数。对于std::string,它使该运算符重载以进行词典比较,即字典顺序。例如:

string("computer") < string("dog")     // true
string("a") < string("abc")            // true

要理解的另一件事是std::sort(以及其他标准容器的排序)如何使用operator<。规则是:

  • 如果a < b,则表示排序顺序中的a早于b
  • 否则,a要晚于b,要么ab在排序顺序中相同。

如果需要区分最后两种情况(即a是否晚于b,或者它们是否相等),则可以检查b < a。如果a < b && b < a意味着它们是平等的。

不要担心正在使用哪种排序算法,或者它是如何做的。您的代码只需要确保其operator<函数返回falsetrue,如上所述。排序算法将使用该信息来生成排序结果。

所以,回到你在代码中看到的那一行:

if(length1 == length2)
     return (first < second); 

return length1 < length2;

这意味着:

  • 如果长度不相等,则较短的长度在排序顺序中排在第一位
  • 如果长度相等,那么字典中第一个出现在排序顺序中的第一个。

因此,如果该集合为dog car cheese boat dog,则排序顺序为car dog dog boat cheese

答案 2 :(得分:1)

评论区域中的问题表明您希望MyOrder::operator()交换实际元素。这不是真的。您的MyOrder仿函数用于比较std::set内部的值,您不需要知道。通过这种方式,您可以抽象std::set的实施细节,并以MyOrder仿函数的形式提供您的排序标准。因此,您可以使用相同的仿函数,例如std::sort

int main(void) 
{
   std::vector< std::string> names; 

   names.push_back("Tony Soprano"); 
   names.push_back("Christopher Moltisanti"); 

   std::sort( names.begin(), names.end(), MyOrder() );
   std::vector<std::string>::iterator it; 

   for( it = names.begin(); it != names.end(); ++it) 
   { 
      std::cout << *it << std::endl; 
   } 
}

并且不需要知道std::sort如何移动元素。

答案 3 :(得分:-1)

operator()的运算符重载使您的类MyOrder的实例可以被调用,就好像它是一个函数一样。具有operator()的班级也称为仿函数()应用程序运算符。

您可以通过这种方式将自定义排序标准应用于算法 - std::sort将在您的班级MyOrder::operator()( std::string, std::string)的实例上使用对MyOrder的调用来询问如何处理这两个字符串。

现在我们将根据长度进行排序,并在长度相等的情况下使用字母顺序。

#include <iostream>
#include <set> 
#include <iterator>


struct MyOrder
{
   bool operator()( const std::string &first, const std::string &second) 
   { 
      size_t length1 = first.length();
      size_t length2 = second.length();
      if ( length1 == length2) return first < second;
      return ( length1 < length2);
   }
};

其余的一样(有一些纠错,MyOrder而不是Myorder)

int main(void) 
{
   std::set< std::string, MyOrder> names; 

   names.insert("Tony Soprano"); 
   names.insert("Christopher Moltisanti"); 

   std::set<std::string>::iterator it; 

   for( it = names.begin(); it != names.end(); ++it) 
   { 
      std::cout << *it << std::endl; 
   } 
}

http://ideone.com/1zTAn7