为什么C ++函数对象需要引用类型成员变量?

时间:2013-03-17 06:51:21

标签: c++ function-object

这是一个新手C ++问题。我正在阅读维基百科中的“功能对象”一文。本文在C ++中有一个类似于以下内容的示例:

struct printClass {
  int &count;

  printClass(int &n) : count(n) {}

  void operator()(int &i) const {
      count++;
      cout << i << "[" << count << "] ";
  }
};

int main(int argc, char** argv) {
    vector<int> a(5, 7);
    a[4] = -1;
    a.resize(10, 3);
    int state = 0;
    for_each(a.rbegin(), a.rend(), printClass(state));
}

我有两个问题:

  1. 当count是常规变量而非引用类型时,为什么编译失败? Demo

  2. 为什么编译失败我将ctor更改为以下内容? Demo

    printClass(int &n) { count = n; }

  3. 感谢。

    编辑:谢谢你的解释。我看到以下版本也有效。是否有理由选择一个而不是另一个?

    struct printClass {
      int count;
    
      printClass(int n) { count  = n; }
    
      void operator()(int &i) {
          count++;
          cout << i << "[" << count << "] ";
      }
    };
    

    编辑:根据iammilind的回复,这里是使用const_cast<int &>的第3版。

    struct printClass {
      int count ;
    
      printClass(int n) : count(n) {}
    
      void operator()(int &i) const {
          const_cast<int &>(count)++;
          cout << i << "[" << count << "] ";
      }
    };
    

1 个答案:

答案 0 :(得分:4)

  

(1)当count是常规变量而不是a时,为什么编译失败   参考类型?

这是一个非常有趣的问题。问题应该是,为什么代码在count被声明为引用时编译。 :)

常规变量失败,因为int countconst限定函数operator()(int &i) const;内无法修改。

参考文献略有不同。在您的代码中,您将方法声明为const,这意味着引用count的{​​{1}}现在无法引用任何其他内容。
但由于引用的性质,这无论如何都不可能:)。初始化后无法更改引用绑定 i只是检查您是否正在更改operator()与其他任何内容的绑定?答案永远不是。因为count更改了count++引用的值而不是绑定。

在您的代码中,count成员方法是否为const并不重要。

int& countint& count;相关联,并尝试自行模拟情况。

  

(2)为什么编译失败我将ctor更改为以下内容?
  int* const p_count;

因为初始化时必须将引用赋给变量。在简单的例子中;

CountFrom(int &n) { count = n; }

另外,在int i, &r; // error, because 'r' not initialized r = i; // this is not initialization but a copy 内处理引用变量时,应格外小心。因为很容易弄乱它们的范围和有效性 例如,class的有效性取决于count的范围。

编辑:在第二次编辑之后,了解该版本的工作原理非常简单。
因为i现在是一个简单的变量。与引用不同,它可以在构造函数的初始化列表中从初始化中跳过 此外count的{​​{1}}正确性已消失,因此const中的任何成员变量现在都可以在其中进行修改。

如果您要声明其中operator()成员“必须”更改(除非任何变量为class或您使用,否则您应该选择成员方法的const版本class)。在所有其他情况下,使用成员方法的普通版本。它们都可以共存,具体取决于您的业务逻辑。这是一个广泛的问题,为此有另一个线程是值得的。