4

这是一个新手 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 是常规变量而不是引用类型时编译失败?演示

  2. 为什么它无法编译它我将其更改ctor为以下?演示

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

谢谢。

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

struct printClass {
  int count;

  printClass(int n) { count  = n; }

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

编辑:根据 iammilind 的回复,这里是第 3 个版本,也可以使用const_cast<int &>.

struct printClass {
  int count ;

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

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

1 回答 1

4

(1) Why does it fail to compile when count is a regular variable not a reference type?

This is a very interesting question. The question should be rather, why the code compiles when count is declared as a reference. :)

The regular variable fails because int count is not modifiable inside a const qualified function operator()(int &i) const;.

References are little different. In your code you are declaring the method as const, which means that count which is referring to i, now cannot refer to anything else.
But that's anyway not possible due to nature of references :). One cannot change reference binding after the initialization.
operator() just checks whether you are changing the binding of count to anything else or not? And the answer is always no. Because count++ changes the value referred by count and not the binding.

In your code, it doesn't matter if a member method is const or not when it comes to int& count.

Relate int& count; to int* const p_count; and try to simulate the situation on your own.

(2) Why does it fail to compile it I change the ctor to the following?
CountFrom(int &n) { count = n; }

Because reference must be assigned to a variable while initialization. In simple example;

int i, &r;  // error, because 'r' not initialized
r = i;  // this is not initialization but a copy

On a side note, you should be extra careful when you are dealing with reference variables inside a class. Because it's easy to mess up with their scope and validity.
For example, here the validity of count is dependent on the scope of i.

Edit: After your 2nd edit, it's very trivial to know why that version works.
Because count is now a simple variable. It can be skipped from initialization in the initializer list of the constructor unlike reference.
Moreover the const correctness of the operator() is gone, so any member variable of the class can now be modified inside it.

You should choose a const version of the member method, if you want to state that no class member "must" change inside it (unless any variable is mutable or you use const_cast). In all other cases use the normal version of the member method. They both can co-exist as well depending on your business logic. This is a bit of a broad question and it's worth to have another thread for this.

于 2013-03-17T06:54:59.493 回答