演算子オーバーロード (C++をもう一度)
[最終更新] (2019/06/03 00:43:08)
最近の投稿
注目の記事

基本的な代入演算子

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

二項演算子の補足事項

この続きが気になる方は

演算子オーバーロード (C++をもう一度)

残り文字数は全体の約 27 %
tybot
100 円
関連ページ
    サンプルコード クラスのメンバ関数のフレンド登録などを行うためにクラスの相互参照が発生することがあります。このような場合はクラスの不完全型を宣言することで解決します。 my_class.h #ifndef MY_CLASS_H_20141223_0137_ #define MY_CLASS_H_20141223_0137_ #include "my_friend_class.h" // 「1
    概要 自動微分というアルゴリズムによって関数の微分値を求める例を記載します。本ページでは、一階微分を対象としており、高階微分は考えません。また簡単のため、関数の出力は一つのテンソルであり、入力となる一つ以上のテンソルおよび出力となる一つのテンソルの階数は零である例を考えます。 更に、関数は、微分可能な関数からなる合成関数であることを仮定します。これは自動微分の応用先の一つである、ディープラーニ