Version 16.14
コンストラクタのオーバーロード
「前回はオーバーロードについて説明しました」
『関数は、同じ名前で引数の違う関数を作れる、と』
「そして渡した引数でどの関数が呼ばれるかが決まる、というわけです」
『それだけなら簡単よね』
「それだけなら、ね」
『う”』
「というわけで、まずはコンストラクタのオーバーロードについて説明しま
す」
『コンストラクタのオーバーロード、引数の違うコンストラクタ……ん?』
「そう、実はこれまでの例で何度も出てきています。ここまでで説明してき
たコンストラクタの復習も兼ねて見ていきます」
// Data.h
// CDataクラス。
class CData
{
public:
// private メンバ変数。
int m_iData;
public:
// 引数のないコンストラクタ。
CData();
// コピーコンストラクタ。
CData( const CData &p_rcData );
// 引数が int 型のコンストラクタ。
CData( int p_i );
// 引数が int 型2つのコンストラクタ。
CData( int p_i1, int p_i2 );
};
// Data.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
// 引数のないコンストラクタ。
CData::CData()
: m_iData( 0 )
{
}
// コピーコンストラクタ。
CData:: CData( const CData &p_rcData )
: m_iData( p_rcData.m_iData )
{
}
// 引数が int 型のコンストラクタ。
CData::CData( int p_i )
: m_iData( p_i )
{
}
// 引数が int 型2つのコンストラクタ。
CData::CData( int p_i1, int p_i2 )
: m_iData( p_i1 + p_i2 )
{
}
「全部で4つのコンストラクタがあります」
・引数のないコンストラクタ
・コピーコンストラクタ
・引数が int 型のコンストラクタ
・引数が int 型2つのコンストラクタ
『あれ? デフォルトコンストラクタはないの?』
「ないよ」
『……あー、そりゃそうだよね、コンストラクタ作ったらなくなっちゃうん
だから』
「そういうこと。デフォルトコンストラクタは〈コンストラクタがない時に
だけ存在する見えないコンストラクタ〉だから、コンストラクタがあったら
ないし、あっても見えないから」
『ここに出てくるわけないね……』
「話を戻すと、このようにコンストラクタも、他のメンバ関数と同じように
オーバーロードすることができます」
『でも、コンストラクタって関数を呼ぶ、って感じじゃないからいまいち
実感が沸かないかも』
「それは言えるかもね。使用例はこうなります」
// 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 cData2( cData );
// int 型引数を持つコンストラクタを呼び出します。
CData cData3( 100 );
// int 型引数2つを持つコンストラクタを呼び出します。
CData cData4( 100, 200 );
return 0;
}
「渡す初期値によって、コンストラクタが変わる感じかな」
・何も渡さない → 引数のないコンストラクタ
・同じクラス → コピーコンストラクタ
・int型変数や整数リテラル → 引数が int 型のコンストラクタ
・int型変数や整数リテラル2つ → 引数が int 型2つのコンストラクタ
「このように、何を渡すかによって呼ばれるコンストラクタが変わることに
なります」
『これも、他のオーバーロードと同じように、渡した型に近いものが選ばれ
るの?』
「そう。型が同じならその方、ないなら近い型のメンバ関数が呼ばれます。
どれか分からない場合にはコンパイルエラーになります」
『前回のと同じってわけね。……質問!』
「はい火美ちゃん」
『引数のないコンストラクタを呼んでる所って、こうじゃダメ?』
// 引数のないコンストラクタを呼び出します。
CData cData();
「だめなんです」
CData cData();
// コンパイルエラー:
// error C2664: '__thiscall CData::CData(const class CData &)' :
// 1 番目の引数を 'class CData (__cdecl *)(void)' から
// 'const class CData &' に変換できません。
// 理由: 'class CData (__cdecl *)(void)' から 'const class CData'
// へは変換できません。
// コンストラクタはソース型を持てません、またはコンストラクタの
// オーバーロード レゾリューションがあいまいです。
『な、なんかよく分からないエラーが……』
「実際、これはできるようにして欲しかったんだけど、仕様上できないんだ
よね。だから諦めるしかないかな」
『むー……あ、もうひとつ質問!』
「はい火美ちゃん」
『 = 使ってもできるんだよね、コンストラクタ呼ぶの』
「はいできます」
// 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 cData2 = cData;
// int 型引数を持つコンストラクタを呼び出します。
CData cData3 = 100;
// int 型引数2つを持つコンストラクタを呼び出します。
CData cData4( 100, 200 );
return 0;
}
「このように、引数がひとつのコンストラクタのみ、 = 演算子で初期化す
ることができます。してることは、さっきの例と同じだからね」
『これでコンストラクタが呼ばれるっていうのも不思議だよね……』
「 C++言語の仕様は不思議なところ多いからね」
『だよね、コピーコンストラクタだって、とっても特別なコンストラクタ
って気がするんだけど、なんか他のコンストラクタと同じような感じだよ
ね』
「そういうものが多いかも。普通のプログラムのように見えて、特別な意味
があるあるものとか」
『そういうのがよく分からない……』
「それはもう、片っ端から試してみて、コンパイルエラーを取り除きながら
憶えていくしかないかもね」
『う”……』
/*
Preview Next Story!
*/
『こういう、特別な意味のって難しい……』
「普通のメンバ関数に見えるからね」
『そうそう。少し違うとダメだし、憶えてないといけないし』
「その一番典型的な例が演算子のオーバーロードかな」
『あーあれもよく分からなかった!』
「というわけで次回」
< Version 16.15 演算子のオーバーロードの復習 >
『につづく!』
「復習だけど、コンストラクタの例とかを踏まえつつ、だといいかも」
『そういえばそういうとこ似てる感じ……?』