operator : 演算子という意味があります。
今回は構造体同士の足し算をする方法を書きます。
D3DXVECTOR3などで
vec=vec1+vec2;が可能なのはオペレーターがオーバーロードされているからです。
[0回]
・ソース
//実際に作ってみます。 ソースをじっくり見てください。
#include <stdio.h>
// int型x,y,zのメンバを持つ構造体
struct Pos3D
{
int x,y,z;
Pos3D operator+(const Pos3D& _r)
{
Pos3D tmp;
tmp.x = x + _r.x;
tmp.y = y + _r.y;
tmp.z = z + _r.z;
return tmp;
}
// a倍したx,y,zを表示する
void print(int a){printf("%d,%d,%d \n",x*a,y*a,z*a);}
// コンストラクタ
Pos3D(int _x,int _y,int _z)
{
x=_x;
y=_y;
z=_z;
}
Pos3D(){x=y=z=0;}
};
void main()
{
Pos3D pos,pos1(1,2,3),pos2(4,5,6);
pos.print(1);
pos=pos1+pos2; // オペレーター「+」の呼び出し
printf("%d,%d,%d",pos.x,pos.y,pos.z);
}
/*
---出力---
0,0,0
5,7,9
*/
・概要
pos変数がprint関数を引数1で呼び出し。 同じように、
pos1変数が+関数を引数pos2で呼び出し
のようになっています。
これで+はマスターです。
・ひとつの式で複数の+が呼ばれた時の処理の流れ
一つ定義するだけで複数の+演算子にも対応することができます。
引き算なども定義してやることでバリエーションを増やすことができます。
pos=pos1+pos2-(pos3+pos1)*pos2; こんな事もできます。
・明示的にオペレーターオーバーロード関数の呼び出し
pos=pos1+pos2; // ☆2
pos=pos1.operator+(pos2); // ☆1
☆1と☆2は等価の式です。
・ちょっとしたテクニック
例えば、D3DXVECTOR3の変数二つの長さを知りたい場合。
D3DXVECTOR3 vec1,vec2;
float len=D3DXVec3Length( &(vec1-vec2) );
vec1-vec2から得られる一時変数tmpを関数の引数として渡すことができます。
他にも、一時変数から関数を呼び出せます。
Pos3D pos1,pos2;
(pos1+pos2).print(1);
・注意点
+演算子なのにマイナスの働きをさせることが可能になりますが、
分かりにくくなってしまうのであまりオススメしません。
例を挙げると、リバースイテレーターが一応あります。
・まとめ
構造体同士を足し算したときに、どういう結果が得られるかが簡単に想像しやすいようなオペレータを定義しましょう。
逆に言うと、下のプログラムの場合
Mylist lis;
lis+=5; // これで自分のリストに5を入れれる
上のような仕様だとわかりにくいです。
今回は算術演算子でしたが、比較演算子・代入・添字などいろいろな演算子を定義できます。
byリーダ和田
PR
COMMENT
それでも神に抗うというの?
処理なんでもできるけどオペレータから予想される処理じゃないとまずいですよね
そうするとかなり限られてくると思うのですが
具体的にゲームプログラミングで使うような例えを複数教えてもらえると助かります
No Title
私はパズルゲームを3D空間で作り、
マスで管理するのでint型のx,y,zが必要になり
上に上げたような構造体を作るとすごく便利です。
漆黒の堕天使様の言うとおりで、
予想される処理じゃないと絶対によろしくないです。
それに、既に色々用意されているクラスがあるので、定義することは少ないと思います。
でも、知ることでクラスをカスタムすることができます。
ということでほんの一例をあげます。
「operator =」
これは自分で定義しなくてもコンパイラが勝手にメンバ変数をコピーしてくれるものを作ってくれるので、あえて自分で定義する必要はないです。
でも、純粋にメンバー変数同士をコピーされると困った事象が発生する場合があります。
それはメンバ変数のポインタにメンバ関数内でnewする場合です。
#include <stdio.h>
struct mycls
{
int* k;
mycls(){
k=new int[5];
for(int i=0 ; i<5 ; ++i)
{
k[i]=i;
}
}
};
void main()
{
mycls pos,pos1;
pos.k[4]=10;
pos1=pos; // ☆
printf("%d",pos1.k[4]);
}
☆の行の呼び出しで、
pos1の*kが開放されないままposの*kがコピーされるので、
pos1内のコンストラクタで*kにnewして作ったポインタがさせなくなり
開放することができなくなります。
なのでこれを解消するには、
コピーされる前に削除します。
const mycls& operator=(const mycls& _r)
{
delete[] k;
k=_r.k;
}
それとコピーを禁止する方法もあります。
それは=演算子をprivateに定義します。
前のoperator=の文を消して、このように改良します。
private:
const mycls& operator=(const mycls& _r){}
privateにoperator=を呼ぶことで外部からは呼び出すことができなくなります。
のようにして解決しないと開放できなくなるメモリが出てきます。
他に、スマートポインタだと=演算子の中で参照カウンタがインクリメントするのもあります。
「キャスト演算子」
自分のクラスを特定のクラスにキャストするときの演算子です。
struct D3DXVECTOR3
{
D3DXVECTOR3(){}
D3DXVECTOR3(float _x,float _y,float _z)
{
x=_x;_y=y;_z=z;
}
float x,y,z;
};
struct Pos3D
{
int x,y,z;
operator D3DXVECTOR3() { // ☆
D3DXVECTOR3 tmp(x,y,z);
return tmp;
}
};
void main()
{
D3DXVECTOR3 vec;
Pos3D pos;
vec=pos; // ここでキャスト演算子が呼ばれる
}
operator [型名]()
特定の型にキャストされるときに呼ばれます。
D3DXCOLORはDWORDのキャスト演算子を持ってたりします。
もう2度と飛べない