Version 16.13
オーバーロードの復習
「今回はオーバーロードについて復習します」
『関数の引数が違うっていうのだよね。結構何度もやったよね』
「まず普通の関数のオーバーロードについては Version 11.19 ( No.219 )
で説明しました」
『その前にもあったよね』
「普通の関数よりも、演算子のオーバーロードを先に説明していたからね。
Version 8.11 ( No.153 ) 、 Version 11.20 ( No.220 ) 、
Version 11.21 ( No.221 ) で説明しました」
『おー、3回も』
「でもその分ちょっとバラバラになっちゃったんでもう一度復習します」
『はーい』
「まず、関数のオーバーロードとは、引数の違う同じ名前の関数を作ること
を言います」
// Data.h
// CDataクラス。
class CData
{
public:
// private メンバ変数。
int m_iData;
public:
// SetData()メンバ関数1。
void SetData( int p_i );
// SetData()メンバ関数2。
void SetData( double p_d );
};
「SetData()メンバ関数が2つ存在します。この2つのメンバ関数は引数が
違っていて、ひとつはint型、もうひとつはdouble型になっています」
『同じ名前だけど、引数が違うってことね』
「メンバ関数の定義もそれぞれ別に作ります」
// Data.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
// SetData()メンバ関数1。
void CData::SetData( int p_i )
{
m_iData = p_i;
OutputDebugString( "CData::SetData( int )\n" );
}
// SetData()メンバ関数2。
void CData::SetData( double p_d )
{
m_iData = (int)p_d;
OutputDebugString( "CData::SetData( double )\n" );
}
『見た目は普通のメンバ関数ね』
「実際、オーバーロードって見た目的には特に違いないかも。使う方も、普
通にメンバ関数を呼び出すのと同じです」
// 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;
cData.SetData( 100 );
// CData::SetData( int )
cData.SetData( 1.0 );
// CData::SetData( double )
}
「どちらのメンバ関数が呼び出されるかは、渡された引数によって異なりま
す」
cData.SetData( 100 );
// CData::SetData( int )
cData.SetData( 1.0 );
// CData::SetData( double )
「このように、渡した値の型と、同じ引数の関数が選択されます」
『引数で決まるってことは、戻り値では決まらないんだよね』
「そういうこと。たとえば、以下のようなメンバ関数はダメです」
// CDataクラス。
class CData
{
public:
// private メンバ変数。
int m_iData;
public:
int GetData();
double GetData();
// コンパイルエラー:
// error C2556: 'double __thiscall CData::GetData(void)' :
// オーバーロード関数の戻り値は異なっていますが、
// 引数リストは同一です。
};
『引数リスト、つまり引数が同じじゃダメってことね。でもこういう
メンバ関数は便利そうなのに』
「確かにね。でも戻り値を受け取らない場合もあるから、そういう場合も考
えると難しいかな」
『確かに戻り値で選択するのって難しい……あれ? でもさ、演算子の
オーバーロードで戻り値の型ってのなかったっけ』
「 Version 11.20 ( No.220 ) で説明した、型変換演算子のオーバーロード
の話だね。あとで説明するけど、これは特例かな」
『普通の場合と同じって考えちゃダメってことね。もひとつ質問』
「はい火美ちゃん」
『さっき型が同じものってあったけど、本当に同じ型じゃなくても呼び出せ
るよね。引数が int 型で、そこに char 型の変数渡すとか』
「うん、できるよ」
『ってことは、その時に〈似た引数でオーバーロード〉されてたら、どっち
が呼ばれるとかって決まってるの?』
「基本的には〈近い方〉が呼ばれます」
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
char ch = 100;
// CData クラスの変数を宣言します。
CData cData;
cData.SetData( ch );
// CData::SetData( int )
return 0;
}
『あ、 int 型の方が呼ばれた』
「渡した値が char 型だと、 int 型と double 型なら int 型の方が近いか
らね。ただ、どれが呼ばれるか決められない場合もあります。そういう場合
にはコンパイルエラーになります」
『たとえばどんな場合?』
「ポインタの型でオーバーロードされていて、そこに NULL が渡された場合
とか」
// Data.h
// CDataクラス。
class CData
{
public:
// private メンバ変数。
int m_iData;
public:
// SetData()メンバ関数1。
void SetData( int *p_pi );
// SetData()メンバ関数2。
void SetData( double *p_pd );
};
// Data.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
// SetData()メンバ関数1。
void CData::SetData( int *p_pi )
{
m_iData = *p_pi;
OutputDebugString( "CData::SetData( int * )\n" );
}
// SetData()メンバ関数2。
void CData::SetData( double *p_pd )
{
m_iData = (int)( *p_pd );
OutputDebugString( "CData::SetData( double * )\n" );
}
「このように、 int 型のポインタと、 double 型のポインタで
オーバーロードするとします。この状態で、 SetData()メンバ関数に NULL
を渡すとコンパイルエラーになります」
// 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;
cData.SetData( NULL );
// コンパイルエラー:
// error C2668: 'SetData' :
// オーバーロード関数の呼び出しを解決することができません。
return 0;
}
『あー、これだとどっちが呼ばれるかって分からないね』
「こういうふうに、はっきりと分からない場合にはエラーになります」
/*
Preview Next Story!
*/
『この辺は復習だし、分かりやすいかも』
「これはシンプルな例だからね」
『あー、確かに演算子のとか複雑なのも多いよね』
「というわけで次回」
< Version 16.14 コンストラクタのオーバーロード >
『につづく!』
「まずは手始めにコンストラクタから」
『う、あの見えないやつが出てくると難しそう……』