Version 16.19
型変換演算子のオーバーロード
「今回は最後のオーバーロード、型変換演算子のオーバーロードについて説
明します」
『一度やってるんだよね』
「 Version 11.20 ( No.220 ) で説明したけど、今回はその復習。まずは例
から」
// Data.h
// CDataクラス。
class CData
{
public:
// public メンバ変数。
int m_iData;
// 型変換演算子のオーバーロード。
operator int();
};
// Data.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
// 型変換演算子のオーバーロード。
CData::operator int()
{
return m_iData;
}
// Main.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
CData cData;
cData.m_iData = 100;
// 型変換演算子のオーバーロードを使用します。
int i = cData;
char pch[256];
sprintf( pch, "%d\n", i );
OutputDebugString( pch );
// 100
return 0;
}
「まず、【型変換演算子】っていうのは、具体的に言うとキャストのこと」
『キャストって、 (int)i とかのキャスト?』
「それもそうだし、そうはっきりと書かないキャストも含みます」
『はっきり書かないキャスト?』
「たとえば int 型の変数に char 型の値を代入したときとか、そういう、
型は違うんだけど変換して渡せる、そういうものもキャストに含むんです」
『そういうキャストも全部ひっくるめて、型変換演算子、って言うと?』
「そういうこと。演算子、っていうのには抵抗あるかもしれないけどね」
『うん、抵抗ある』
「変数の値に対して何らかの処理をして結果を返す、っていう点では演算子
なんだよね。演算子の性質としては、 ! 演算子とかが近いかも」
『 TRUE と FALSE を入れ替える?』
「そう。あれと同じ、値を変換して返す、そういう意味での演算子」
『うーん、なんかちょっと納得いかないけど……』
「まぁ名前の問題だから、それほど深く考えなくてもいいかも。今回の例で
は、以下の箇所が、型変換演算子を使用している箇所になります」
// 型変換演算子のオーバーロードを使用します。
int i = cData;
「 CData クラスの変数から int 型の変数に代入しようとしているので、
コンパイラは CData から int へ型変換しようとします」
『でも普通できないよね』
「そう、できません。そこで、型変換演算子をオーバーロードします。以下
のメンバ関数が、 int 型の型変換演算子のオーバーロードです」
// 型変換演算子のオーバーロード。
CData::operator int()
{
return m_iData;
}
『な、なんかこれまた変な書き方だよね……』
「書き方は、以下のようになります」
クラス::operator 型()
「こうすると、〈クラス〉が〈型〉に変換されようとしたときに、この
メンバ関数が呼び出されます」
『 m_iData を返すって事は、その値が i に渡されるんだ』
「そういうこと。こんな感じに、型変換演算子のオーバーロードは〈ただひ
とつだけメンバ変数を持っていて、それが目に見えて分かる〉ような場合に
だけ作るような感じかな」
『どゆこと?』
「メンバ変数がふたつあったら?」
『……どっち返せばいいかわからないね』
「でしょう。それよりは、 CString クラスみたいに」
『何返すのか分かり切ってる!』
「っていうクラスの方が型変換演算子のオーバーロードを使うのに向いてい
る、ってこと」
『なるほどねー。……? 質問!』
「はい火美ちゃん」
『これってメンバ関数だけど、普通の関数にはできる?』
「ううん、できません。まだ説明していなかったけど、 = 演算子とか、こ
の型変換演算子は、メンバ関数としてしか作れないんです」
『げ、そうなんだ』
「だから」
operator int( CData &p_rcData )
{
return p_rcData.m_iData;
}
「みたいなのは作れません」
『なるほど、じゃあ次の質問!』
「はい火美ちゃん」
『さっきの使ってるとこ見て思ったんだけど』
// 型変換演算子のオーバーロードを使用します。
int i = cData;
『これって、わざわざ型変換演算子のオーバーロードしなくても、
= 演算子のオーバーロードしちゃえばいいんじゃない?』
「さっき説明したけど」
『あ”、そういえばそうだね、 = 演算子はメンバ関数じゃないといけない
けど、そしたら int 型のメンバ関数にしなきゃいけなくて……無理だね』
「それ以前に、この例は = 演算子を使っているけど、 int 型変数を宣言し
ているわけだから、実際には……」
『?』
「つまり、こういうこともできるから」
// 型変換演算子のオーバーロードを使用します。
int i( cData );
『あ! そうだった、コンストラクタ呼んでるんだ!』
「そういうこと。変数の初期化をするときの = 演算子は、実際には引数が
1つのコンストラクタを呼び出しているのと同じこと」
『 Version 16.12 ( No.339 ) でやったのだ』
「だから、 = 演算子じゃなくて、コンストラクタの話として考えなきゃい
けないわけ」
『あー。……でも、 int 型のコンストラクタとか作れないし』
「 int 型ならね。でも普通のクラスなら」
『作れちゃう……? じゃあさじゃあさ、その普通のクラスのコンストラクタ
で CData クラス受け取ってさ、 CData クラスでは……あれ?』
「うん、つまり、その普通のクラスを CData2 だとすると」
// 型変換演算子のオーバーロードを使用します。
CData2 cData2 = cData;
「ってした時に、 CData2( CData &p_rcData ) が呼ばれるのか、
CData::operator CData2() が呼ばれるのか分からない、ってことでしょ?」
『……??? なんだかよく分からなくなってきた』
「……というわけで次回に続く」
『ええっ!?』
/*
Preview Next Story!
*/
『なんで続くのー?』
「実は、これはとても重要な問題なんです」
『そなの? ちょっと思い付いただけなんだけど』
「そういうところが重要なんだよね、実は」
『意外』
「というわけで次回」
< Version 16.20 オーバーロードの選択 >
『につづく!』
「逆に、気付かないと実はすごくまずいという」
『う”、意外意外』