Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

C++ オペレーターオーバーロード(演算子の多重定義) まとめ

スポンサードリンク

f:id:fa11enprince:20200628231818j:plain

C++で演算子の多重定義は使用頻度がそんなに多くはないものですが、
いざ書く時、あれれ、戻り値は参照にしていいの?とか
引数はconstつけるべきなの?参照渡しでいいの?とか
いろいろ悩んでしまってもうこの際丸暗記してしまおう!
っていうような作戦に出ようと思ったのですが、
それを書いてあるようなサンプルのサイトがなかなか見つからないので、
とりあえず自分のほうでまとめてみました。
Javaでこれが使えればね……equals()とか書くたびにイラッとします。
演算子の多重定義はなれていないので、
もしかすると、あまりよくない書き方をしているかもしれません。

ソースコード


実行結果

foo1 ------ 
	a_:   10	b_:   20	c_:   30
foo2 ------ 
	a_:   20	b_:   10	c_:   30
foo3 ------ 
	a_:   40	b_:   10	c_:   20
operator-() ------ 
	a_:  -40	b_:  -10	c_:  -20
operator-() ------ 
	a_:  -40	b_:  -10	c_:  -20
operator=() foo4 = foo1 ------ 
	a_:   10	b_:   20	c_:   30
foo1 < foo2 ------ 
	false
foo2 < foo1 ------ 
	false
foo1 = foo2 ------ 
	true
foo1 < foo5 ------ 
	true
operator+() foo1 + foo2 ------ 
	a_:   30	b_:   30	c_:   60
operator+() foo1 - foo2 ------ 
	a_:  -10	b_:   10	c_:    0
operator*() foo1 * foo2 ------ 
	a_:  200	b_:  200	c_:  900
operator+=() foo1 += foo2 ------ 
	a_:   30	b_:   30	c_:   60
operator-=() foo1 -= foo2 ------ 
	a_:   10	b_:   20	c_:   30
operator*=() foo1 *= foo2 ------ 
	a_:  200	b_:  200	c_:  900

補足

使用頻度が高いオペレーターオーバーロードは
operator=(), operator<(), operator==(),
その他かな……。
他はあんまり使わない。ライブラリ作成者なら使うかもしれません。

2014/11/27 更新
齊藤 (id:SaitoAtsushi)さんのご意見・アドバイスを戴き、
単項演算子の返却の仕方を変更しました。
単項の-演算子を使うことにより呼ぶたびに結果が変わるのは
プリミティブな型と一貫性がないというご指摘をいただきました。
ツッコミを戴けるのは非常にうれしい限りです。

2014/12/04 更新
yoh (id:yohhoy)さんにいろいろ教えていただき、修正+追記。
その要点は
単項+演算子、単項-演算子、単項*演算子、単項/演算子、
二項+演算子、二項-演算子、二項*演算子、二項/演算子、
つまり'+', '-', '*', '/'の演算子のオーバーロードですが、
C++11ではconst返ししないほうがいいということでした。

理由はconstを付けてしまうとムーブセマンティクスが働かないからです。
こう書くのがよさそうです。

class Foo {
    // ... いろいろ省略
public:
    Foo(int a, int b, int c) {
        a_ = a;
        b_ = b;
        c_ = c;
    }
    // ... いろいろ省略
    Foo operator+() const { return Foo(a_, b_, c_); }
    Foo operator+(const Foo &rhs) const
    {
        return Foo(a_ + rhs.a_, b_ + rhs.b_, c_ + rhs.c_);
    }
    // ... いろいろ省略
};

ちなみにconstを付けないとどうなるかというと
上記のコードを使って次のように書けてしまいます。

int main()
{
    Foo foo1(10, 20, 30);
    Foo foo2(20, 10, 30);
    Foo foo3(40, 10, 30);

    +foo1 = foo2;         // foo1は変わらない
    (foo1 + foo2) = foo3; // 当然foo1, foo2は変わらない

    return 0;
}

上のはおかしいんだけどコンパイルが通ってしまう…。
こういう弊害がありますが
こんな変な書き方することはないのでconstはなくてもいいんじゃないかなー
それよりムーブセマンティクスが働かないほうがMOTTAINAIです。
ちなみに代入演算子系の'=', '+=', '-=', '*=', '/='は

    (foo1 = foo2) = foo3;

という書き方を許してやってよい(例えばint型の変数はこれができる)ので
constを付けないほうが良いっぽいです。