【问题标题】:Understanding operator() overloading理解 operator() 重载
【发布时间】:2014-09-11 20:16:45
【问题描述】:

我正在尝试理解重载方法,尤其是关于 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; 
   } 
 } 

【问题讨论】:

  • operator() 应该是 const(虽然这不是必需的)
  • Myorder 与 MyOrder 不同
  • functionoid 应该是严格的弱排序,这意味着当且仅当第一个参数绝对位于第二个参数的“左侧”时,它才会返回 true。如果它们相等,那么第一个并不总是“在左边”,所以它应该返回 false。如果感到困惑,想想operator&lt; 做了什么。
  • 哪一部分你不明白? Myorder::operator() 是如何工作的,或者它是如何传递给 std::set 的?
  • @Slava 我假设问题是operator() 函数内用 cmets 编写的问题

标签: c++ operator-overloading


【解决方案1】:

&lt; 运算符表示小于,其计算结果为true 或false。例如:

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

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

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

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

要了解的另一件事是std::sort(和其他标准容器的排序)如何使用operator&lt;。规则是:

  • 如果a &lt; b 表示a 在排序顺序中比b 更早出现
  • 否则,要么a 晚于b,要么a 和b 在排序顺序上相等。

如果它需要区分最后两种情况(即a是否晚于b,或者它们是否相等),它可以检查b &lt; a。如果a &lt; b &amp;&amp; b &lt; a 表示它们是相等的。

不用担心正在使用哪种排序算法,或者它是如何工作的。您的代码只需要确保其operator&lt; 函数返回false 或true,正如刚才所述。排序算法将使用该信息来生成排序结果。

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

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

return length1 < length2;

意思是:

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

所以如果集合是dog car cheese boat dog,那么排序顺序就是car dog dog boat cheese。

【讨论】:

    【解决方案2】:

    set&lt;&gt; 的第二个模板参数(如果提供)是一个运算符,用于确定您希望元素如何排序。默认运算符是使用std::less&lt;&gt; 的结果,如果第一个参数小于第二个参数,它将返回true。使用默认比较运算符时,集合中的元素 e0 .. eN 将被排序,使得ei ei+1 为真。

    () 的运算符重载使MyOrder 的实例能够像函数一样被调用。通过提供MyOrder 作为第二个模板参数,您可以将集合中元素的顺序更改为如果order 是MyOrder 的一个实例,order(ei, ei+1) 为真。

    MyOrder 已实现如下行为:

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

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

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

    因此,如果该集合包含{ "m", "zz", "aaa" },并且您想将"ii" 添加到其中,它将被放置在"m" 之后(因为它比它长),但在"zz" 之前(因为它是按字母顺序排列的)小于它)。所以结果会变成{ "m", "ii", "zz", "aaa" }。

    【讨论】:

      【解决方案3】:

      cmets 区域中的问题表明您希望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 是如何移动元素的。

      【讨论】:

        【解决方案4】:

        operator() 的运算符重载使您的类 MyOrder 的实例能够像函数一样被调用。带有operator() 的类也称为函子。 () 是 application 运算符。

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

        现在我们将根据长度进行排序,如果长度相等,则使用字母顺序。

        #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

        【讨论】:

        • 原版是正确的,你只是去掉了长度相等时的二级字典排序
        • @MattMcNabb 请查看
        • @0d0a 我做了审查。反对票不是我的。但是您的代码仍然与删除 cmets 并修复错字的 OP 相同;我认为他正在寻求解释为什么 operator() 函数有效
        • DOWNVOTER 愿意解释一下吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-08
        • 2010-12-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多