Version 16.07
ポインタと参照のおさらい
「今回は、クラスを使う上でのポインタと参照についておさらいします」
『これまで散々使ってるから大丈夫だと思うけど』
「それは文字列とかの話でしょ」
『うん、 char 型の配列とか文字列のコピーとかばっちり! だと思うよ』
「クラスの場合、それとは違う知識が必要だから、そのあたりを中心に説明
します」
『違う知識?』
「そう、違う知識」
『そういうもんなんだ……』
「といってもまずは基本的なところから。 Version 4.10 ( No.060 ) から
のポインタ編は分かってるね」
『うん、文字列関係は大丈夫』
「で、逆にクラスの場合にはこういう、アドレスを直接操作する、といった
使い方はしないようにします」
『え、そうなの?』
「もちろん中に文字列を持っていたり、構造体だったりする場合には必要な
こともあるけど、基本的にはそういう細かい操作はしない、って考えて」
『なんで?』
「そうだね、たとえば private メンバ変数」
『外からアクセスできないメンバ変数ね。あ……もしかして、アドレス直で
指定するとアクセスできちゃう?』
「そういうこと。 private とか public っていうのは、コンパイル時にし
か機能しないから、アドレスを直接指定されたりすると全然機能しないんで
す」
『そりゃまずいね……』
「クラスには、プログラムを安全に作るための色々な仕組みがあるんです。
private メンバ変数もそう。でもアドレスやポインタを駆使したプログラム
はそういうものを台無しにしちゃうから」
『使わないようにする、ってことね』
「そういうこと。だから、クラスを中心にした時、ポインタは」
・変数の複製を作らずに渡す
・引数経由で値を返す
・ポリモーフィズム
「といった目的に使います」
『ぽ……ぽりもおふぃずむ?』
「それはもうちょっと後でね。まずは基本的な所から。 CData クラスが、
次のように一般的なクラスだとします」
// Data.h
// CDataクラス。
class CData
{
private:
// private メンバ変数。
int m_iData;
public:
// m_iData の getter 。
int GetData() const;
// m_iData の setter 。
void SetData( int p_iData );
};
// Data.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
// m_iData の getter 。
int CData::GetData() const
{
return m_iData;
}
// m_iData の setter 。
void CData::SetData( int p_iData )
{
m_iData = p_iData;
}
『 m_iData メンバ変数と、 getter と setter があるクラスね』
「これを、ポインタを使って関数に渡す場合」
// Main.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
void Set100( CData *p_pcData )
{
//セットします。
p_pcData->SetData( 100 );
}
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
// CDataクラスの変数を宣言します。
CData cData;
cData.SetData( 100 );
// OutputData()に渡します。
Set100( &cData );
char pch[256];
sprintf( pch, "%d\n", cData.GetData() );
OutputDebugString( pch );
// 100
return 0;
}
「 Set100() 関数の引数を CData クラスのポインタにします。そうするこ
とで、 Set100() 関数には cData 変数のアドレスが渡されます」
『すると?』
「まず、新しい変数が作られなくなります。引数がポインタではない場合、
つまり」
void Set100( CData p_cData )
「となっていた場合、新しく CData クラスの変数 p_cData が作られて、
渡した cData 変数のメンバ変数に格納されている値がコピーされます。
でも」
void Set100( CData *p_pcData )
「と、ポインタの場合には CData クラスの変数は作られず、 cData 変数の
アドレスが渡されるだけなので、変数はひとつだけになります」
『それってメモリが消費されないからいい、ってこと?』
「それもあるけど、それ以外にも色々なメリットがあります。この点につい
てはもう少し先に。加えて、ここではポインタで渡されているので、
実際には cData 変数へアクセスできます。
//セットします。
p_pcData->SetData( 100 );
「 p_pcData には cData 変数のアドレスが格納されてるから、これは」
cData.SetData( 100 );
「と同じになります」
『外から渡した変数にアクセスできるってわけね』
「この2つが」
・変数の複製を作らずに渡す
・引数経由で値を返す
「に該当します」
『残りのポリモーフィズムは?』
「それはもっと後で」
『もっと……』
「さて、基本的に、クラスをポインタで使う場合にはこの2つのメリットの
ために使用します。ただ、ポインタの場合」
・ポインタに渡す際にはアドレスを渡さなければならないため【&】を付ける
・メンバにアクセスするのに【.】ではなく【->】を使用する
・アドレスを渡すためアドレス操作をしてしまう可能性がある。
「といった面でちょっと面倒です」
『というわけで参照を使うわけね』
「そういうこと。 Set100() 関数を参照版に変えると、以下のようになりま
す」
// Main.cpp
#include <Windows.h>
#include <stdio.h>
#include "Data.h"
void Set100( CData &p_rcData )
{
//セットします。
p_rcData.SetData( 100 );
}
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
// CDataクラスの変数を宣言します。
CData cData;
cData.SetData( 100 );
// OutputData()に渡します。
Set100( cData );
char pch[256];
sprintf( pch, "%d\n", cData.GetData() );
OutputDebugString( pch );
// 100
return 0;
}
「参照の場合、メンバにアクセスする時に【->】ではなく【.】を使用しま
す」
//セットします。
p_rcData.SetData( 100 );
「渡す時も、【&】を付けないで渡せます」
// OutputData()に渡します。
Set100( cData );
『ポインタらしくなく使えるわけね。ポインタと参照、どっち使うといい
の?』
「基本的にはポインタ。でも一部の場合には参照」
『なにその曖昧な基準』
「参照の使いどころはこれから説明していくから、普通はポインタを使っ
て、これから説明する、コンストラクタや演算子のオーバーロードでは
使う、っていうスタンスかな」
/*
Preview Next Story!
*/
『この辺は復習だから軽いわねー』
「でも次回は……」
『? const メンバ関数? それも知ってるけど』
「でも、この const メンバ関数、実は……」
『……実は?』
「というわけで次回」
< Version 16.08 const メンバ関数 >
『につづく!』
「阿鼻叫喚の地獄絵図が待っています」
『まぢで?』
「まぢで」