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