TENKAIKEN Storehouse

Contents ♪

C++ 演算子のオーバーロード 2024.08.05
オブジェクト間の+演算のオーバーロード
時分秒のクラスTimeに、+演算子のオーバーロードを実装する。
operator+()は、計算結果を新たしいTimeクラスのインスタンスを生成して返す。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time operator+(const Time &t);
    void show();
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time Time::operator+(const Time &t)
{
    int s = t.sec + sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

void Time::show()
{
    printf("%02d\'%02d\"%02d\n",
        sec / 3600, (sec % 3600) / 60, (sec % 3600) % 60);
}

int main()
{
    Time t1(1, 35, 12);
    Time t2(2, 41, 25);
    Time t = t1 + t2;
    t.show();           // 04'16"37
}
C++ 演算子のオーバーロード 2024.08.05
オブジェクト+数値型のオーバーロード
時分秒のクラスTimeに、+演算子のオーバーロードを実装する。
Timeクラスと整数値の秒数の両方を加算するoperator+()を実装する。これにより、
Time = Time + Time
Time = Time + 秒数
のようにできる。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time operator+(const Time &t);
    Time operator+(int s);
    void show();
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time Time::operator+(const Time &t)
{
    int s = t.sec + sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

Time Time::operator+(int s)
{
    s += sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

void Time::show()
{
    printf("%02d\'%02d\"%02d\n",
        sec / 3600, (sec % 3600) / 60, (sec % 3600) % 60);
}

int main()
{
    Time t1(1, 35, 12);
    Time t2(2, 41, 25);
    Time t = t1 + t2 + 30;
    t.show();           // 04'17"07
}
C++ 演算子のオーバーロード 2024.08.05
数値型+オブジェクトのオーバーロード
Timeクラスと整数値の秒数の両方を加算するoperator+()を実装し、更に
Time = 秒数 + Time 
ができるように、秒数にTimeを加算するグローバルスコープでの演算子のオーバーロード関数を定義する。グローバルスコープの演算子のオーバーロード関数は2つの引数を取り、
A + B --> operator+(A, B)
のようになる。
グローバルスコープのオーバーロード関数は、Timeクラスのprivateメンバにアクセスできるように、Timeクラスでfriend宣言している。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time operator+(const Time &t);
    Time operator+(int s);
    friend Time operator+(int sec, const Time& t);
    void show();
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time Time::operator+(const Time &t)
{
    int s = t.sec + sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

Time Time::operator+(int s)
{
    s += sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

void Time::show()
{
    printf("%02d\'%02d\"%02d\n",
        sec / 3600, (sec % 3600) / 60, (sec % 3600) % 60);
}

Time operator+(int s, const Time& t)
{
    s += t.sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

int main()
{
    Time t1(1, 35, 12);
    Time t = 145 + t1;  
    t.show();           // 01'37"37
}
C++ 演算子のオーバーロード 2024.08.05
-の単項演算のオーバーロード
時分秒のクラスTimeに、-演算子の二項と単項演算のオーバーロードを実装する。
Timeクラスと整数値の秒数の両方を加算するoperator+()と、同様な減算のoperator-()と、単項マイナスのoperator-()を両方実装している。単項演算の方は引数を持たず、thisの単項でマイナスにしたTimeを生成して返す。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time operator+(const Time &t);
    Time operator+();
    Time operator-(const Time &t);
    Time operator-();
    void show();
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time Time::operator+(const Time &t)
{
    int s = sec + t.sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

Time Time::operator+()
{
    return *this;
}

Time Time::operator-(const Time &t)
{
    int s = sec - t.sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

Time Time::operator-()
{
    return Time(-sec / 3600, (-sec % 3600) / 60, (-sec % 3600) % 60);
}

void Time::show()
{
    printf("%02d\'%02d\"%02d\n",
        sec / 3600, (sec % 3600) / 60, (sec % 3600) % 60);
}

int main()
{
    Time t1(3, 14, 17);
    Time t2(1, 39, 43);
    Time t = t1 - t2;
    t.show();           // 01'34"34
    t = -t2 + t1;
    t.show();           // 01'34"34
}
C++ 演算子のオーバーロード 2024.08.05
++インクリメント演算子のオーバーロード
時分秒のクラスTimeに、インクリメント演算子++のオーバーロードを実装する。
インクリメント(デクリメント)演算子は単項演算なので引数のないオーバーロード関数定義になるが、後置の場合は引数の定義に「int」を指定することになっている。これは、どのようなクラスでもintである。後置の場合は、加算前にthisをコピーしたオブジェクトを返している。
前置のオーバーロードは、演算結果が自分のインスタンスそのものへの反映なので、thisの参照を返している。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time& operator++();     // 前置
    Time operator++(int);   // 後置
    void show();
private:
    int sec;
};


Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time& Time::operator++()
{
    ++sec;
    return *this;
}

Time Time::operator++(int)
{
    Time tmp = *this;
    ++*this;        // operator++()
    return tmp;     // 加算前のコピーを返す
}

void Time::show()
{
    printf("%02d\'%02d\"%02d\n",
        sec / 3600, (sec % 3600) / 60, (sec % 3600) % 60);
}

int main()
{
    Time t(3, 14, 17);
    (++t).show();       // 03'14"18
    t++.show();         // 03'14"18
    t.show();           // 03'14"19
}
C++ 演算子のオーバーロード 2024.08.05
関係演算子のオーバーロード
時分秒のクラスTimeに、関係演算を実装する。
関係演算の結果はブールなので、戻り値はboolである。この例にない<や>=、論理演算子も同様である。
#include <iostream>
using namespace std;

class Time {
public:
    Time(int h, int m, int s);
    bool operator==(const Time &t);
    bool operator!=(const Time &t);
    bool operator>(const Time &t);
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

bool Time::operator==(const Time &t)
{
    return sec == t.sec;
}

bool Time::operator!=(const Time &t)
{
    return !(*this == t);   // operator==(t)の否定
}

bool Time::operator>(const Time &t)
{
    return sec > t.sec;
}

int main()
{
    Time t1(3, 14, 17);
    Time t2(2, 56, 30);
    if (t1 == t2)
        cout << "T1 == T2" << endl;
    else if (t1 != t2)
        cout << "T1 != T2" << endl;
    if (t1 > t2)
        cout << "T1 > T2" << endl;
}
C++ 演算子のオーバーロード 2024.08.05
配列参照[]のオーバーロード
配列の[]をオーバーロードできる。
配列の添字はoperator[]()の引数で与えることができ、通常の配列ならばこれは整数だが、文字列やクラスのような添字を取るような配列にすることが可能になる。この例では、STLにもある連想配列のようなクラスDictを簡単に実現している。
#include <cstdio>
#include <cstdlib>
#include <cstring>

class Dict {
public:
    Dict(int _len);
    ~Dict();
    int length() { return len; };
    char*& operator[](const char* key);
    void show();
private:
    int len;
    int cnt;
    char** keys;
    char** vals;
};

Dict::Dict(int _len)
{
    keys = (char**)calloc(len, sizeof(char*));
    vals = (char**)calloc(len, sizeof(char*));
    len = _len;
    cnt = 0;
}

Dict::~Dict()
{
    free(keys);
    free(vals);
}

char*& Dict::operator[](const char *key)
{
    for (int i = 0; i < len; i++) {
        if (keys[i] && strcmp(keys[i], key) == 0)
            return vals[i];
    }
    keys[cnt++] = (char*)key;
    return vals[cnt - 1]; 
}

void Dict::show()
{
    for (int i = 0; i < len; i++) {
        if (keys[i] != 0)
            printf("%s = %s\n", keys[i], vals[i]);
    }
}

int main()
{
    Dict dict(3);
    dict["ABC"] = (char*)"123";
    dict["DEF"] = (char*)"456";
    dict["GHI"] = (char*)"789";
    dict["DEF"] = (char*)"999";
    dict.show();
    printf("ABC->%s\n", dict["ABC"]);
    return 0;
}
C++ 演算子のオーバーロード 2024.08.05
型キャストのオーバーロード
int()やdouble()のような型のキャストで行う変換演算をオーバーロードできる。
変換演算子のオーバーロード関数は、戻り値も引数も定義しない。オーバーロードの実装では変換する型を返すようにする。例のように、
(int)xint(x)
のいずれの型変換が行われるときにオーバーロードが適用される。
#include <cstdio>

class Time {
public:
    Time(int h, int m, int s);
    Time operator+(const Time &t);
    operator int();
private:
    int sec;
};

Time::Time(int h, int m, int s)
{
    sec = h * 3600 + m * 60 + s;
}

Time Time::operator+(const Time &t)
{
    int s = t.sec + sec;
    return Time(s / 3600, (s % 3600) / 60, (s % 3600) % 60);
}

Time::operator int()
{
    return sec;
}

int main()
{
    Time t(1, 35, 12);
    printf("sec=%d\n", int(t));     // sec=5712
    printf("sec=%d\n", (int)t);     // sec=5712
}