C++ で代入演算子のオーバーロードを実装する

胡金庫 2023年10月12日
C++ で代入演算子のオーバーロードを実装する

この記事では、C++ で代入演算子のオーバーロードを実装する方法のいくつかの方法について説明します。

C++ でコピー代入演算子を使用してオーバーロードされた代入演算子を実装する

C++ は、演算子をオーバーロードする機能を提供します。これは、組み込み演算子が特定のクラスで呼び出されたときにカスタム関数を呼び出す一般的な方法です。これらの関数には、operator で始まり、その後に特定の演算子記号自体が続く特別な名前を付ける必要があります。たとえば、カスタム代入演算子は、operator= という名前の関数で実装できます。代入演算子は通常、左側のオペランドへの参照を返す必要があります。ユーザーがコピー割り当て演算子を明示的に定義しない場合、コンパイラーが自動的に生成することに注意してください。生成されたバージョンは、ヒープメモリに手動で割り当てられたデータメンバーがクラスに含まれていない場合に非常に機能します。各要素を対応するオブジェクトメンバーに割り当てることで、配列メンバーを処理することもできます。ただし、次のサンプルコードに示すように、動的メモリデータメンバーを処理する場合には欠点があります。

#include <iostream>
#include <string>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

class Person {
 public:
  Person() {
    name = new string;
    surname = new string;
  };
  Person(string n, string s) {
    name = new string(std::move(n));
    surname = new string(std::move(s));
  }
  Person(Person &p) {
    name = new string(*p.name);
    surname = new string(*p.surname);
  }

  ~Person() {
    delete name;
    delete surname;
  }

  void renamePerson(const string &n, const string &s) {
    name->assign(n);
    surname->assign(s);
  };

  void printPerson() { cout << *name << " " << *surname; }

 private:
  string *name;
  string *surname;
};

int main() {
  Person P1("Buddy", "Rich");
  Person P2 = P1;

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  P1.renamePerson("Jay", "Roach");

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  Person P3;
  P3 = P1;
  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  P1.renamePerson("Liam", "White");

  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  exit(EXIT_SUCCESS);
}

出力:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Liam White

上記のコードは、copy-constructor のみを明示的に定義しているため、P1 オブジェクトの内容が P3 オブジェクトに割り当てられると、誤った動作が発生します。P1.renamePerson 関数への 2 回目の呼び出しは、P3 オブジェクトのデータメンバーを変更するべきではなかったが、変更したことに注意してください。これに対する解決策は、オーバーロードされた代入演算子、つまりコピー代入演算子を定義することです。次のコードスニペットは、同じクラスの 2つのオブジェクトを正しくコピーして割り当てることができるバージョンの Person クラスを実装しています。ただし、copy-assignment 関数の if ステートメントは、オブジェクトがそれ自体に割り当てられている場合でも、演算子が正しく機能することを保証することに注意してください。

#include <iostream>
#include <string>
#include <utility>
#include <vector>

using std::cout;
using std::endl;
using std::string;
using std::vector;

class Person {
 public:
  Person() {
    name = new string;
    surname = new string;
  };
  Person(string n, string s) {
    name = new string(std::move(n));
    surname = new string(std::move(s));
  }
  Person(Person &p) {
    name = new string(*p.name);
    surname = new string(*p.surname);
  }

  ~Person() {
    delete name;
    delete surname;
  }

  Person &operator=(const Person &p) {
    if (this != &p) {
      *name = *(p.name);
      *surname = *(p.surname);
    }
    return *this;
  }

  void renamePerson(const string &n, const string &s) {
    name->assign(n);
    surname->assign(s);
  };

  void printPerson() { cout << *name << " " << *surname; }

 private:
  string *name;
  string *surname;
};

int main() {
  Person P1("Buddy", "Rich");
  Person P2 = P1;

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  P1.renamePerson("Jay", "Roach");

  P1.printPerson();
  cout << endl;
  P2.printPerson();
  cout << endl;

  Person P3;
  P3 = P1;
  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  P1.renamePerson("Liam", "White");

  P1.printPerson();
  cout << endl;
  P3.printPerson();
  cout << endl;

  exit(EXIT_SUCCESS);
}

出力:

Buddy Rich
Buddy Rich
Jay Roach
Buddy Rich
Jay Roach
Jay Roach
Liam White
Jay Roach
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C++ Class