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));
}

2つの質問があります:

  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)countが参照型ではなく通常の変数であるのに、なぜコンパイルに失敗するのですか?

これは非常に興味深い質問です。count問題はむしろ、が参照として宣言されたときにコードがコンパイルされる理由です。:)

修飾された関数int count内で変更できないため、通常の変数は失敗します。constoperator()(int &i) const;

参照は少し異なります。あなたのコードでは、メソッドをとして宣言しています。これはconst、を参照しているものが、他のものを参照できないことを意味します。 しかし、参照の性質上、それはとにかく不可能です:)。初期化後に参照バインディングを変更することはできません。のバインディングを他のものに変更しているかどうかを確認するだけですか?そして答えは常にノーです。バインディングではなく、によって参照される値を変更するためです。counti

operator()countcount++count

コードでは、メンバーメソッドがであるconstかどうかは関係ありませんint& count

自分で状況をシミュレートしてみてくださいint& count;int* const p_count;

(2)コンパイルに失敗するのはなぜですか?ctorを次のように変更しますか?
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ます。

編集:2回目の編集後、そのバージョンが機能する理由を知るのは非常に簡単です。は単純な変数だ
からです。count参照とは異なり、コンストラクターの初期化子リストの初期化からスキップできます。
さらに、のconst正確性operator()が失われたため、canの任意のメンバー変数をそのclass内部で変更できるようになりました。

メンバーがその内部で「変更する必要がない」constことを示したい場合は、メンバーメソッドのバージョンを選択する必要があります(変数が変更されているか、を使用している場合を除く)。他のすべての場合は、通常バージョンのメンバーメソッドを使用します。ビジネスロジックによっては、両方が共存することもできます。これは少し広い質問であり、これについて別のスレッドを用意する価値があります。classmutableconst_cast

于 2013-03-17T06:54:59.493 に答える