LoginSignup
5
1

More than 3 years have passed since last update.

代入演算子は*thisへの参照を戻すようにしよう - Effective C++ 第3版 10項-

Last updated at Posted at 2020-03-21

 はじめに

Effective C++ 第3版の10項 48ページから勉強していきます。
今回は、「代入演算子は*thisへの参照を戻すようにしよう」についです。

Effective C++ 第3版 - 10項 代入演算子は*thisへの参照を戻すようにしよう -

前置き

今回は、「自分で作成したクラスにコピー代入演算子を実装する場合のルール」について学んでいきます。

今回の勉強

コピー代入演算子

コピー代入演算子は、以下のようにつなげて使用することができます。

int x, y, z;
x = y = z = 15; // 代入をつなげる

コピー代入演算子は、右結合である。
 →右から左へ結合していく
そのため、上のような連続代入は、以下のように解釈されます。
まず、15がzに代入され、
次に、その結果(更新されたz)がyに代入され、
最後に、その結果(更新されたy)がxに代入される。

x = (y = (z = 15));

これは、コピー代入演算子が「左辺への参照」を戻すことで実現されています。

自分で作成したクラスにコピー代入演算子を実装する場合は、以下のようになります。

class Widget {
 public:
  /* コンストラクタ */
  Widget(int x, int y) : x_(x), y_(y) {}

  /* コピー代入演算子 */
  Widget& operator=(const Widget& rhs) { // 戻り値の方は、自身のクラスの参照型
    x_ = rhs.x_;
    y_ = rhs.y_;
    return *this; // 左辺への参照を返す(自分自身を返す)
  }

  int getX() { return x_; }
  int getY() { return y_; }

 private:
  int x_;
  int y_;
};

また、通常の代入(=)に限らず、全ての代入演算子(+=, -= など)に上のように書く必要があります。
また、仮引数の型が違っても、同様に *this を返す必要があります。

class Widget {
 public:
  ...

  Widget& operator+=(const Widget& rhs) { // +=, -=, *= でも*thisを返す。
    std::cout << __func__ << std::endl;
    x_ += rhs.x_;
    y_ += rhs.y_;
    return *this;
  }

  /* 引数がint型 */
  Widget& operator*=(int rhs) { // 引数の型が違う場合でも *thisを返す。
    std::cout << __func__ << std::endl;
    x_ *= rhs;
    y_ *= rhs;
    return *this;
  }

 private:
  ...

};

これらのように、「コピー代入演算子は、*thisへの参照を戻す」というのは、
すべての組み込み型とすべての標準ライブラリの型(string, vector, など)が従っているそうです。

サンプルコード

以下に、勉強で使用したコードを示します。

#include <iostream>

class Widget {
 public:
  Widget(int x = 0, int y = 0) : x_(x), y_(y) {}
  Widget& operator=(const Widget& rhs) {
    std::cout << __func__ << std::endl;
    x_ = rhs.x_;
    y_ = rhs.y_;
    return *this;
  }
  Widget& operator+=(const Widget& rhs) {
    std::cout << __func__ << std::endl;
    x_ += rhs.x_;
    y_ += rhs.y_;
    return *this;
  }

  Widget& operator*=(int rhs) {
    std::cout << __func__ << std::endl;
    x_ *= rhs;
    y_ *= rhs;
    return *this;
  }

  int getX() { return x_; }
  int getY() { return y_; }

 private:
  int x_;
  int y_;
};

int main() {
  std::cout << "10_first.cpp" << std::endl;
  int x, y, z;
  x = y = z = 15;

  Widget b;
  b = Widget(1, 1);
  std::cout << "\noperator= Widget(1, 1)" << std::endl;
  std::cout << "b.x : " << b.getX() << std::endl;
  std::cout << "b.y : " << b.getY() << std::endl;

  b += Widget(2, 2);
  std::cout << "\noperator+= Widget(2, 2)" << std::endl;
  std::cout << "b.x : " << b.getX() << std::endl;
  std::cout << "b.y : " << b.getY() << std::endl;

  b *= 4;
  std::cout << "\noperator*= 4" << std::endl;
  std::cout << "b.x : " << b.getX() << std::endl;
  std::cout << "b.y : " << b.getY() << std::endl;
}

実行結果

実行結果
10_qiita.cpp

operator= Widget(1, 1)
b.x : 1
b.y : 1

operator+= Widget(2, 2)
b.x : 3
b.y : 3

operator*= 4
b.x : 12
b.y : 12

まとめ

今回は、自分で作成したクラスにコピー代入演算子を実装する場合のルールについて学びました。

覚えておくこと

  • 代入演算子は*thisへの参照を戻すようにしよう。

参考文献

[1] https://www.amazon.co.jp/gp/product/4621066099/ref=dbs_a_def_rwt_hsch_vapi_taft_p1_i0

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1