演算子のオーバーロード

演算子のオーバーロード

発展編6日目までの知識があれば、C++プログラマーとしては、かなりのことができるでしょう。ただ、よりエレガントなプログラムを作成するという意味では、ここで紹介する演算子のオーバーロードは欠かせません。

通常、+や、=のような演算子は、通常、数値や文字列などのような、ある特定のデータ型やクラスにしか利用できません。ところが、C++言語では、これらの演算子に機能を拡張して、さまざまなクラスに演算処理を実装したり、もともとある機能を変更できたりするのです。

サンプルプログラム

では、実際にサンプルを通して、演算子のオーバーロードとはどのようなものなのかを実際にみてみることにしましょう。少し長いですが、以下のサンプルコードを実行してみてください。

listex7-1:Vector2.h
#ifndef _VECTOR2_H_
#define _VECTOR2_H_

#include 
#include 

using namespace std;

class Vector2{
public:
	double x;
	double y;
public:
	//	=演算子のオーバーロード
	Vector2& operator=(const Vector2& v);
	//	+=演算子のオーバーロード
	Vector2& operator+=(const Vector2& v);
	//	-=演算子のオーバーロード
	Vector2& operator-=(const Vector2& v);
};

//	+演算子のオーバーロード
Vector2 operator+(const Vector2&, const Vector2&);
//	-演算子のオーバーロード
Vector2 operator+(const Vector2&, const Vector2&);
//	*演算子のオーバーロード
Vector2 operator*(const double,const Vector2& v);

#endif // _VECTOR2_H_
Vector2.cpp
#include "vector2.h"

//	+演算子のオーバーロード
Vector2 operator+(const Vector2& v1,const Vector2& v2)
{
	Vector2 v;
	v.x = v1.x + v2.x;
	v.y = v1.y + v2.y;
	return v;
}
//	-演算子のオーバーロード
Vector2 operator-(const Vector2& v1,const Vector2& v2)
{
	Vector2 v;
	v.x = v1.x - v2.x;
	v.y = v1.y - v2.y;
	return v;
}
//	スカラー倍
Vector2 operator*(const double d, const Vector2& v)
{
	Vector2 r;
	r.x = d * v.x;
	r.y = d * v.y;
	return r;
}
//	=演算子のオーバーロード
Vector2& Vector2::operator=(const Vector2& v)
{
	x = v.x;
	y = v.y; 
	return *this; 
}
//	+=演算子のオーバーロード
Vector2& Vector2::operator+=(const Vector2& v)
{
	x += v.x;
	y += v.y;
	return *this;
}
//	-=演算子のオーバーロード
Vector2& Vector2::operator-=(const Vector2& v)
{
	x -= v.x;
	y -= v.y;
	return *this;
}
main.cpp
#include <iostream>
#include "vector2.h"

using namespace std;

void vec(string, Vector2&);

int main(){
	Vector2 v1,v2,v3;
	//	ベクトルに値を代入
	v1.x = 1.0;
	v1.y = 2.0;
	v2 = v1;			//	値を代入
	v3 = 4.0 * v1;		//	ベクトルのスカラー倍
	vec("v1=", v1);
	vec("v2=", v2);
	vec("v1 + v2=", v1 + v2);
	vec("v3=", v3);
	v3 += v1;			//	代入演算子(+=)
	vec("v3=",v3);
	v1 -= v2;			//	代入演算子(-=)
	vec("v1=", v1);
	return 0;
}

void vec(string vecname,Vector2& v)
{
	cout << vecname << "(" << v.x << "," << v.y << ")" << endl;
}
実行結果
v1=(1,2)
v2=(1,2)
v1 + v2=(2,4)
v3=(4,8)
v1=(5,10)
v2=(0,0)

このサンプルは、簡単な2次元ベクトルクラスVector2を作ったものです。C++には、もともとそういったクラスは存在しませんが、main.cppを見ればわかるように、あたかもそういった演算をできるクラスがもともとあるような使い方が可能になっています。

代入、および代入演算子のオーバーロード

演算子のオーバーロードをするには、以下のように宣言を行います。

演算子のオーバーロードの宣言
戻り値の型 operator演算子(引数…)

まず、クラス内に定義されている、代入関連の演算子、=および、+=-=を見てみましょう。これらはいずれも、クラス内にメンバ変数として定義されています。

引数として与えられた、他のVector2クラスのインスタンスへの参照が渡され、このインスタンスから、値を取得し、代入、および何らかの計算をして、メンバ変数である、xyの値を変更しています。

そして、最後に*thisを返すことにより、自分自身への参照を戻り値として返しています。いったいなぜそのようなことをする必要があるのでしょうか?これは特に決められたことではありませんが、なるべく基本データ型の演算に近づけるためには、大変有効な方法です。なぜなら、

複数回の代入演算子の仕様
v1 = v2 = v3

のように、複数回の代入を同時に行うような処理の場合、一回目の代入の結果が、そのまま2回目に代入されるため、このような処理を行うには、Vector2&を返すことが有用なのです。

+,-,*演算子

続いて、+,-,*演算子のケースを見てみましょう。これらは、クラス内には記述されていません。理由は、これらの演算は、Vector2とVector2および、doubleとVeoctor2の演算で、戻り値としてVector2クラスのインスタンスを得るものであることから、すでにあるインスタンスの値を変化させる代入演算子とは性質が違うことに由来します。

このように、演算子のオーバーロードには、クラス内に定義する方法と、クラス外に定義する方法が存在します。

最後に

まとめ

以上で、C++の基本の発展編を終わりにしたいと思います。C++に関する話題はこれですべてが終わりというわけではなく、ここで紹介しきれなかった機能も少なからず存在しますが、このサイトに紹介していることに関してしっかりと理解していれば、C++でかなり本格的なプログラミングをするこことが可能です。