Cpp クラス thisポインタ
C++に戻る
本来の表記は「C++(Cpp) クラス thisポインタ」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。 |
※このページではC++にのみ存在する機能として、記事タイトルがC++ クラス thisポインタになっています。
クラス thisポインタ
thisポインタとは、自分自身を指し示すポインタだと言われており、初心者が聴くとなんとなくワケがわからない教えられ方をあちらこちらでされているように見受けます。自分自身?それって何だ?
その前に、thisというキーワードのポインタ変数が定義したクラスの中で、クラスを作成しただけで使える状態になっているということについては理解しなければならないです。そして、そのthisという名前のポインタ変数が何を示しているか?
自分自身
ポインタについての説明はC ポインタに記述したので、あまり多くは語りません。ポインタについてイマイチまだわかっていないかもしれない。自分にはまだはやかったかもしれないと思った場合は読み返すか、他のサイトで調べるとかが必要になります。
thisっていう名前のポインタ変数が使えるようになっていることは、理解するというか、そういう仕様なんだから納得するしかないとして、自分自身っていう言われ方をするポインタ変数というのがどういうものなのかを示しておきたいと思います。
例えば、わかりやすい例で示せば、以下のような感じのプログラムを動かすことで自分自身という表現の意味を理解できるやもしれません。
ThisPointer001.h
#pragma once
class CThisPointer001
{
public:
CThisPointer001(void);
~CThisPointer001(void);
};
ThisPointer001.cpp
#include "stdafx.h"
#include "ThisPointer001.h"
CThisPointer001::CThisPointer001(void)
{
printf("this Address =%08x\n",this);//★1.thisポインタのアドレス出力
}
CThisPointer001::~CThisPointer001(void)
{
}
Sample_Main.cpp
#include "stdafx.h"
#include "ThisPointer001.h"
int _tmain(int argc, _TCHAR* argv[])
{
CThisPointer001* CThisPointer001_Instance = new CThisPointer001;
printf("CThisPointer001_Instance Address=%08x\n",CThisPointer001_Instance);//★2.変数のアドレス出力
return 0;
}
またしても、サンプルが長くなってしまいましたが、辛抱強く試してみた人がいたとしたら、実行結果は以下のようになったでしょう。
出力結果
this Address =00579108
CThisPointer001_Instance Address=00579108
★1.と★2.でthisポインタの出力と生成したクラスオブジェクトの変数のアドレスが一致しました。これが自分自身ということの意味になります。だから?何ができるのか?
例えば、thisポインタを使って、メンバ関数やメンバ変数を呼び出すことができます。でも、thisポインタを使わなくても呼び出せていました。そしたらthisポインタってのは何の役に立つのか?それはですね。自分自身の中の何かのメンバ変数やメンバ関数であることを明示しなければならない場合があるということにつきます。たとえばメンバ関数ポインタで明示しなければならないパターンを示しました。
自動的に作られるthisというキーワードのポインタ変数は、意図的にthisポインタと同じものを作ることができます。
thisポインタと同じようなものを作るという意味で、プログラムを継ぎ足し変更したりして、以下のように変えてみます。
ThisPointer001.h
#pragma once
class CThisPointer001
{
public:
int mpub_nValue;//★1
CThisPointer001* this2;//★2
void mfpub_SetThis(CThisPointer001* pCThisPointer001_this);//★3
void mfpub_Output1(void);//★4
CThisPointer001(void);
~CThisPointer001(void);
};
ThisPointer001.cpp
#include "stdafx.h"
#include "ThisPointer001.h"
//★5
void CThisPointer001::mfpub_SetThis(CThisPointer001* pCThisPointer001_this){
printf("\n");
printf("■CThisPointer001::mfpub_SetThis\n");
printf("pCThisPointer001_this Address =%08x\n",pCThisPointer001_this);
this2 = pCThisPointer001_this;
printf("this Address =%08x\n",this);
printf("this2 Address =%08x\n",this2);
pCThisPointer001_this->mpub_nValue = 10;//★10.
printf("mpub_nValue =%08d\n",mpub_nValue);
this->mpub_nValue = 100;//★11.
printf("mpub_nValue =%08d\n",mpub_nValue);
mpub_nValue = 2000;//★12.
printf("mpub_nValue =%08d\n",mpub_nValue);
}
//★6
void CThisPointer001::mfpub_Output1(){
printf("\n");
printf("■CThisPointer001::mfpub_Output1\n");
printf("this Address =%08x\n",this);
printf("this2 Address =%08x\n",this2);
printf("mpub_nValue =%08d\n",mpub_nValue);
}
CThisPointer001::CThisPointer001(void)
{
printf("\n");
printf("■CThisPointer001コンストラクタ\n");
printf("this Address =%08x\n",this);
}
CThisPointer001::~CThisPointer001(void)
{
}
Sample_main.cpp
#include "stdafx.h"
#include "ThisPointer001.h"
int _tmain(int argc, _TCHAR* argv[])
{
CThisPointer001* CThisPointer001_Instance = new CThisPointer001;
CThisPointer001_Instance->mfpub_SetThis(CThisPointer001_Instance);//★100
CThisPointer001_Instance->mfpub_Output1();
CThisPointer001_Instance->mpub_nValue = 1000;
printf("\n");
printf("■Main\n");
printf("CThisPointer001_Instance Address=%08x\n",CThisPointer001_Instance);
return 0;
}
そうすると、出力結果は以下のようになります。
■CThisPointer001コンストラクタ
this Address =0094eeb8
■CThisPointer001::mfpub_SetThis
pCThisPointer001_this Address =0094eeb8
this Address =0094eeb8
this2 Address =0094eeb8
mpub_nValue =00000010
mpub_nValue =00000100
mpub_nValue =00002000
■CThisPointer001::mfpub_Output1
this Address =0094eeb8
this2 Address =0094eeb8
mpub_nValue =00002000
■Main
CThisPointer001_Instance Address=0094eeb8
という具合です。
具体的に変更したところの中で重要なところはThisPointer001.hファイルの★1~★4を追加したこと、★5と★6のメンバ関数をプログラムとして追加したことです。
そして、特に確認しておきたいのは★5の関数の引数として、CThisPointer001クラスのメンバ関数の引数として、CThisPointer001クラスのポインタ変数を受け取ることになっている点です。このように自分で自分を受け取るみたいな形でポインタ変数を引数とすることにより、まさにthisポインタと同じようなものを作ったことになります。もちろん、呼び出すときにはメインプログラム側で、実体のある自分自身を引数に受け取らないと、自分自身を示すポインタは作れないので、メインプログラム側の★100のように自分自身を引数にするような組み込みが要求されます。
そうすると、★10のように
pCThisPointer001_this->mpub_nValue = 10;
というような★100で自分自身を受け渡したポインタ変数の中のメンバ変数への代入ができます。クラス内部からのアクセスなので、この代入はプライベートな領域のメンバ変数であっても呼び出すことが出来ます。その確認は自分自身にお任せしたいと思います。
これが自分自身ということになります。★11では、あえてthisポインタを明示したメンバ変数へのアクセス方法を記述しました。★10と同じことをしているというのは、最初のサンプルプログラムで、同じアドレスを保持していたことからも理解してもらえるものと思います。
★12は従来というか、特に意識しなくても自分自身のメンバ変数にアクセスできていることがわかる部分になっています。
thisはポインタと同じようなものを作ったと書きましたが、やはり★12のように省略してもいいし、いつでもthisポインタは使えるという点では、全く同じものを作ることはできません。thisポインタはいつでも使えるという点においては、C++の仕様ですから、この便利さにかなうものもなければ、これと同じ役割のキーワードを新たに作ることも難しいでしょう。常にthisと同じ役割をする別名の変数を作るように動作させるマクロとか作れるのかもしれませんが、それができるかどうかについても自分自身で確かめていただければと思います。それが必要かどうか答えは自分自身で見つけて。
thisポインタが省略できるクラス内でのメンバ関数やメンバ変数の仕組みとかの原理や論理もあると思いますが、そのあたりは自分は理解していません。thisポインタの役割がわかっていれば、プログラムを読み解くことはできると思います。原理や論理を理解しないなんてバカだなぁと思う人はいるかもしれませんが、そういう人と関わるようになったときには積極的に理解していきたいと思います。そのときは優しく教えてくれるといいなぁ。この記事を読まれた若きプログラマは熱意をもって原理や論理にまで追求というか迫ると言うか、そういうようなことをしてもらったほうがいいのかもしれません。
C++に戻る