演算子
スポンサーリンク
オーバーロード可能な演算子
C++ では次の演算子がオーバーロード可能です。
+ - * / % ^ & | ~ ! << >> ++ --
= += -= *= /= %= ^= &= |= <<= >>=
== != < > <= >= && || , ->* -> () []
new delete new[] delete[]
メンバ関数としての定義
次のプログラムは,座標を表す Point クラスに演算子 + を定義した例です。
#include <iostream>
class Point
{
public:
int x;
int y;
Point(int x, int y) : x(x), y(y) { }
Point operator+(const Point& rhs);
};
// 演算子 + を定義
Point Point::operator+(const Point& rhs)
{
return Point(this->x + rhs.x, this->y + rhs.y);
}
int main()
{
Point p(2, 3);
Point q(4, 5);
Point r = p + q; // p.operator+(q) と考える
std::cout << r.x << std::endl; // 出力: 6
std::cout << r.y << std::endl; // 出力: 8
return 0;
}
演算子の定義は,関数の形式で次のように書きます。関数名は operator 演算子 とします。
// 単項演算子
返却型 operator 演算子 () { ... }
// 二項演算子
返却型 operator 演算子 (型 右オペランド) { ... }
引数名には,しばしば lhs (left-hand side), rhs (right-hand side) という名前が使われます。
グローバル関数としての定義
次のプログラムは,グローバル関数として演算子 + を定義した例です。
#include <iostream>
class Point
{
public:
int x;
int y;
Point(int x, int y) : x(x), y(y) { }
};
// 演算子 + を定義
Point operator+(const Point& lhs, const Point& rhs)
{
return Point(lhs.x + rhs.x, lhs.y + rhs.y);
}
int main()
{
Point p(2, 3);
Point q(4, 5);
Point r = p + q; // operator+(p, q) と考える
std::cout << r.x << std::endl; // 出力: 6
std::cout << r.y << std::endl; // 出力: 8
return 0;
}
グローバル関数としてを定義する場合,演算子の定義は次のように書きます。
// 単項演算子
返却型 operator 演算子 (型 オペランド) { ... }
// 二項演算子
返却型 operator 演算子 (型1 左オペランド, 型2 右オペランド) { ... }
出力演算子の定義
次のように出力演算子を定義すると,Point 型の値 p を std::cout << p で出力できるようになります。
#include <iostream>
class Point
{
public:
int x;
int y;
Point(int x, int y) : x(x), y(y) { }
};
// 出力演算子を定義
std::ostream& operator<<(std::ostream& o, const Point& p)
{
o << "(" << p.x << ", " << p.y << ")";
return o;
}
int main()
{
Point p(2, 3);
std::cout << p << std::endl; // 出力: (2, 3)
return 0;
}
前置/後置インクリメント演算子
次のプログラムは,Point クラスに前置/後置インクリメント演算子を定義した例です。
#include <iostream>
class Point
{
public:
int x;
int y;
Point(int x, int y) : x(x), y(y) { }
Point& operator++(); // 前置
Point operator++(int); // 後置
};
// 前置インクリメント
Point& Point::operator++()
{
++this->x; ++this->y;
return *this;
}
// 後置インクリメント
Point Point::operator++(int)
{
Point ret(*this);
++this->x; ++this->y;
return ret;
}
// 出力演算子
std::ostream& operator<<(std::ostream& o, const Point& p)
{
o << "(" << p.x << ", " << p.y << ")";
return o;
}
int main()
{
Point p(1, 5);
std::cout << p << std::endl; // 出力: (1, 5)
std::cout << ++p << std::endl; // 出力: (2, 6)
std::cout << p++ << std::endl; // 出力: (2, 6)
std::cout << p << std::endl; // 出力: (3, 7)
return 0;
}
前置と後置の区別は,引数の有無で区別されます。
後置インクリメント演算子の引数 (int) は,前置と区別するためのダミーの引数です。
この例からわかるように,一般に前置は後置よりも効率がよいと言えます。
C++ において i++ よりも ++i が多用されるのは,このためです。
スポンサーリンク