基本的な代入演算子
#include <iostream>
#include <algorithm>
using namespace std;
class MyClass {
public:
MyClass(int size);
~MyClass();
void operator=(const MyClass& other); // 演算子オーバーロード
public:
int Get(int i);
private:
int m_size;
int* m_intarr;
};
MyClass::MyClass(int size) {
m_size = size;
m_intarr = new int[size];
fill_n(m_intarr, size, 0);
}
MyClass::~MyClass() {
delete[] m_intarr;
}
void MyClass::operator=(const MyClass& other) {
/* 手法 1 */
/* 別変数にnewしてからdelete */
/* - メリット: newに失敗してももとの値は保持される */
/* - デメリット: 解放せずにnewするため失敗しやすくなる */
int* intarr = new int[other.m_size];
delete[] m_intarr; // メモリリークしないように、格納していた値の領域を解放
m_intarr = intarr;
m_size = other.m_size;
copy(other.m_intarr, other.m_intarr + m_size, m_intarr);
/* 手法 2 */
/* ヌルポインタを代入してデストラクタでの delete[] に備える */
/* (ヌルポインタ p を delete p してもエラーにならないという */
/* 古いコンパイラは未対応の比較的新しいC++の仕様) */
/* - メリット: 解放してからnewするため成功しやすい */
/* - デメリット: newに失敗しても元の値は戻せない */
// delete[] m_intarr;
// m_intarr = NULL;
// m_size = 0;
// m_intarr = new int[other.m_size];
// m_size = other.m_size;
// copy(other.m_intarr, other.m_intarr + m_size, m_intarr);
/* だめな手法 */
/* newで失敗すると解放済みなためデストラクタでエラー */
// delete[] m_intarr;
// m_intarr = new int[other.m_size];
// m_size = other.m_size;
// copy(other.m_intarr, other.m_intarr + m_size, m_intarr);
}
int MyClass::Get(int i) {
return m_intarr[i];
}
int main() {
MyClass obj(5);
MyClass obj2(5);
obj2 = obj; // オーバーロードした演算子
cout << obj2.Get(0) << endl;
return 0;
}
[] 演算子
#include <iostream>
using namespace std;
class MyClass {
public:
static const int SIZE = 8; // 静的メンバ定数
public: // [] 演算子のオーバーロード
int& operator[](int i); // 非constオブジェクト用
const int& operator[](int i) const; // constオブジェクト用
private:
const int& At_(int i) const;
private:
int m_intarr[SIZE];
};
int& MyClass::operator[](int i) {
return const_cast<int&>(At_(i)); // constを外す危険なキャスト
}
const int& MyClass::operator[](int i) const {
return At_(i);
}
const int& MyClass::At_(int i) const {
return m_intarr[i];
}
int main() {
MyClass obj;
cin >> obj[0];
cout << obj[0] << endl;
return 0;
}
キャスト演算子
#include <iostream>
using namespace std;
class MyClass {
public: // キャスト演算子のオーバーロード
operator int() const; // [] 演算子と異なり非constオブジェクトとconstオブジェクトで
operator double() const; // constメンバ関数を使い回しても問題にならない。代入などしない。
};
MyClass::operator int() const {
return 2; // サンプルのため値は仮
}
MyClass::operator double() const {
return 2.2; // サンプルのため値は仮
}
int main() {
MyClass obj;
int intval = obj;
cout << intval << endl; //=> 2
cout << (double)obj << endl; //=> 2.2
return 0;
}
二項演算子
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int intval);
public: // 二項演算子のオーバーロード (自分以外に相手を必要とする演算子)
MyClass operator/(const MyClass& rop) const; // rop: right operand
MyClass operator-(const MyClass& rop) const;
public:
operator int() const;
private:
int m_intval;
};
MyClass::MyClass(int intval) :
m_intval(intval)
{
}
MyClass MyClass::operator/(const MyClass& rop) const {
return MyClass(m_intval / rop.m_intval); // テンポラリオブジェクト:
// https://www.qoosky.io/techs/d9a4a9ab57
}
MyClass MyClass::operator-(const MyClass& rop) const {
return MyClass(m_intval - rop.m_intval);
}
MyClass::operator int() const {
return m_intval;
}
int main() {
MyClass objA(10);
MyClass objB(2);
MyClass objC = objA / objB;
cout << (int)objC << endl; //=> 5
cout << objA - objB << endl; //=> 8 (暗黙のキャスト)
return 0;
}
単項演算子
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int intval);
public: // 単項演算子のオーバーロード
MyClass operator-() const;
public:
operator int() const;
private:
int m_intval;
};
MyClass::MyClass(int intval) :
m_intval(intval)
{
}
MyClass MyClass::operator-() const {
return MyClass(-m_intval);
}
MyClass::operator int() const {
return m_intval;
}
int main() {
MyClass obj(5);
cout << -obj << endl; //=> -5
return 0;
}
複合代入演算子
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int intval);
public: // 複合代入演算子のオーバーロード
MyClass& operator+=(const MyClass& rop); // 非constオブジェクトだけを考えてよい
public:
operator int() const;
private:
int m_intval;
};
MyClass::MyClass(int intval) :
m_intval(intval)
{
}
MyClass& MyClass::operator+=(const MyClass& rop) {
m_intval += rop.m_intval;
return *this; // this: 自分自身を指すポインタ
}
MyClass::operator int() const {
return m_intval;
}
int main() {
MyClass objA(2);
MyClass objB(20);
cout << (int)(objA += objB) << endl; //=> 22
return 0;
}
インクリメント/デクリメント演算子
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int intval);
public: // インクリメント演算子のオーバーロード
MyClass& operator++(); // 前置
MyClass operator++(int); // 後置 (int: 前置と区別するため。仕様)
public:
operator int() const;
private:
int m_intval;
};
MyClass::MyClass(int intval) :
m_intval(intval)
{
}
MyClass& MyClass::operator++() {
++m_intval;
return *this;
}
MyClass MyClass::operator++(int) {
MyClass copy = *this;
++m_intval;
return copy;
}
MyClass::operator int() const {
return m_intval;
}
int main() {
MyClass obj(0);
cout << ++obj << endl; //=> 1
cout << obj << endl; //=> 1
cout << obj++ << endl; //=> 1 (2でないことがポイントですね)
cout << obj << endl; //=> 2
return 0;
}
二項演算子の補足事項