単項演算子のオーバーロード

http://www.geocities.jp/ky_webid/cpp/language/017.html

単項の演算子、例えばインクリメントや-1とか+1といった符号などのオーバーロードも可能です。

試してみます。

#include <iostream>

class CNum {
public:
    int m_num;
    CNum (int num);
    int getNum();
    CNum operator-(); // 単項の-演算子
    
};

CNum::CNum(int num) {
    this->m_num = num;
}

int CNum::getNum() {
    return this->m_num;
}

CNum CNum::operator-() {
    CNum tmp(this->m_num);
    tmp.m_num *= -1;
    return tmp;
}

int main() {
    CNum num1(100);
    CNum num2 = -num1;
    
    std::cout << num1.getNum() << std::endl;
    std::cout << num2.getNum() << std::endl;
    return 0;
}
$ main
100
-100

まずは単項の-演算子オーバーロード

元のオブジェクトを変更しないのでtmpを用意して返します。

なので戻り値に参照は使えません。

お次は前置インクリメント(++objのこと)を実装してみます。

#include <iostream>

class CNum {
public:
    int m_num;
    CNum (int num);
    int getNum();
    CNum& operator++(); // 前置インクリメント
};

CNum::CNum(int num) {
    this->m_num = num;
}

int CNum::getNum() {
    return this->m_num;
}

CNum& CNum::operator++() {
    this->m_num++;
    return *this;
}

int main() {
    CNum num1(100);
    
    std::cout << (++num1).getNum() << std::endl;
    std::cout << num1.getNum() << std::endl;
    return 0;
}
$ main
101
101

前置インクリメントはoperator++()で宣言できます。

前置の挙動は先に++してから値を返す仕様なのでthisの値をそのままインクリメントして戻り値にthisを返すだけです。

また、一時変数を利用していないので参照で返すことも可能です。

少しややこしいのが後置インクリメントです。実装してみます。

#include <iostream>

class CNum {
public:
    int m_num;
    CNum (int num);
    int getNum();
    CNum operator++(int); // 後置インクリメント
};

CNum::CNum(int num) {
    this->m_num = num;
}

int CNum::getNum() {
    return this->m_num;
}

CNum CNum::operator++(int) {
    CNum tmp = *this;
    this->m_num++;
    return tmp;
}

int main() {
    CNum num1(100);
    
    std::cout << (num1++).getNum() << std::endl;
    std::cout << num1.getNum() << std::endl;
    return 0;
}
$ main
100
101

まず宣言の仕方がややこしいです。

operator++(int)になります。引数にintを指定していますね。これが無いと前置と後置を区別できないのです。

しかもこれは区別するためだけの引数なので実際の処理では使用しません。

使用しない引数については宣言だけでなく、定義時にもoperator++(int)と書けます。CではコンパイルエラーでしたがC++では省略できるようになりました。

で肝心の実装ですが、後置インクリメントは評価の最後にインクリメントするので戻り値はインクリメント前のものを返さないといけません。

よってtmpを定義し、そちらを戻り値として返しています。なので当然参照で返すことはできません。

こうやって内部の実装を見てみると、後置よりも前置を使った方が良いという理由が良く分かりますね。後置だと余計に変数を定義していることになりますから、戻り値を必要としない処理においては前置を使った方が良いです。