Cpp クラス アクセス指定子 新しいページはコチラ

提供: yonewiki
移動: 案内, 検索
(クラス アクセス指定子)
(クラス アクセス指定子)
131行: 131行:
  
 
メインプログラムや他のクラス内で以下のようにクラスを実際に利用するプログラムを記述すると以下のようになります。
 
メインプログラムや他のクラス内で以下のようにクラスを実際に利用するプログラムを記述すると以下のようになります。
sample_main.cpp
+
と上記のように利用します。_tmain関数からの呼び出し処理がいわゆる外部からの呼び出しにあたる処理になります。クラスを説明した記事でも記sample_main.cpp
 
<syntaxhighlight lang="cpp" line start="1">
 
<syntaxhighlight lang="cpp" line start="1">
 
#include "stdafx.h"
 
#include "stdafx.h"
152行: 152行:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
と上記のように利用します。_tmain関数からの呼び出し処理がいわゆる外部からの呼び出しにあたる処理になります。クラスを説明した記事でも記述しましたが、Access_Specifiers001.hファイルの★1.部分にあるようなm_nValueというint型の変数にはprivateというアクセス指定がなされていて、内部からの呼び出しだけが許されています。したがって、_tmain関数から呼び出すことはできないため、CAccess_Specifiers001_Instance->m_nValue = 120;のように変数の呼び出しをしようとするとコンパイルエラーになります。値を設定するにはSet_m_nValue関数を値を取得するにはGet_m_nValue関数を使うしかないのがCAccess_Specifiers001の取り決めになります。
+
述しましたが、Access_Specifiers001.hファイルの★1.部分にあるようなm_nValueというint型の変数にはprivateというアクセス指定がなされていて、内部からの呼び出しだけが許されています。したがって、_tmain関数から呼び出すことはできないため、CAccess_Specifiers001_Instance->m_nValue = 120;のように変数の呼び出しをしようとするとコンパイルエラーになります。値を設定するにはSet_m_nValue関数を値を取得するにはGet_m_nValue関数を使うしかないのがCAccess_Specifiers001の取り決めになります。
  
  
193行: 193行:
  
 
Visual Studioのメニュー プロジェクトからクラスの追加を選択します。
 
Visual Studioのメニュー プロジェクトからクラスの追加を選択します。
 +
 
[[file:CppClassAdd01.png]]
 
[[file:CppClassAdd01.png]]
  
  
 
表示されたダイアログのクラス名にCIntUnit そして、基本クラスにCAccess_Specifiers001と指定します。継承しない(派生しない)クラスを作るときは基本クラスの欄は何もいれないでクラスを作ることができます。 プロジェクトからクラスの追加を選択します。
 
表示されたダイアログのクラス名にCIntUnit そして、基本クラスにCAccess_Specifiers001と指定します。継承しない(派生しない)クラスを作るときは基本クラスの欄は何もいれないでクラスを作ることができます。 プロジェクトからクラスの追加を選択します。
 +
 
[[file:CppClassAdd02.png]]
 
[[file:CppClassAdd02.png]]
 +
 +
 +
そうすると、CIntUnitは派生したクラスになり、継承と言う技術を使っていて、継承の基本クラスにCAccess_Specifiers001だけが選択されていることになります。クラスの定義は以下のように自動生成されます。
 +
 +
IntUnit.h
 +
<syntaxhighlight lang="cpp" line start="1">
 +
#pragma once
 +
#include "access_specifiers001.h"
 +
class CIntUnit : public CAccess_Specifiers001//★5.継承
 +
{
 +
public:
 +
  CIntUnit(void);
 +
  ~CIntUnit(void);
 +
};
 +
</syntaxhighlight>
 +
★5.の部分で定義されたクラスは派生していないクラスと違って、上記の3行目のようにclass CIntUnit : public CAccess_Specifiers001 としてクラス定義がなされます。これがCAccess_Specifiers001を継承した派生クラスCIntUnitを定義する方法です。
 +
 +
 +
通常の定義したクラスと違って、CIntUnitはCAccess_Specifiers001の機能をすべて持っていて、protectedおよびpublicで定義された関数や変数にはアクセスできるようになっています。CIntUnitは派生してるクラスなのでCAccess_Specifiers001のメンバ変数m_nValueを1000倍してくれる関数が使えます。実際にやってみましょう。まずCIntUnitにCAccess_Specifiers001のmf_m_nValue1000x()を呼び出す関数mf_1000x();を定義してみます。
 +
 +
 +
IntUnit.h
 +
<syntaxhighlight lang="cpp" line start="1">
 +
#pragma once
 +
#include "access_specifiers001.h"
 +
class CIntUnit :
 +
  public CAccess_Specifiers001
 +
{
 +
public:
 +
  void mf_1000x(void);//★6.protectedで定義された関数を使うクラス。
 +
 +
  CIntUnit(void);
 +
  ~CIntUnit(void);
 +
};
 +
</syntaxhighlight>
 +
★6.のようにmf_1000xという関数を作りました。
 +
 +
IntUnit.cpp
 +
<syntaxhighlight lang="cpp" line start="1">
 +
#include "stdafx.h"
 +
#include "IntUnit.h"
 +
 +
void CIntUnit::mf_1000x(){
 +
  mf_m_nValue1000x();//★7._tmain関数では呼び出せなかったが、派生クラスからは呼び出せる。
 +
}
 +
 +
CIntUnit::CIntUnit(void)
 +
{
 +
}
 +
 +
 +
CIntUnit::~CIntUnit(void)
 +
{
 +
}
 +
 +
</syntaxhighlight>
 +
CIntUnit.cppのプログラム部分にmf_1000xの処理として、_tmain関数から作ったクラスでは直接呼べなかったmf_m_nValue1000xを呼び出すように★7.部分のように記述しました。このように派生したクラスからはprotectedでアクセス指定子が宣言されている関数にできるのが派生クラスの権限です。そうするとCIntUnitクラスを使えばCAccess_Specifiers001クラスではできなかった処理ができることになります。このようにprotectedのレベルで定義された関数は派生クラスによって正しい使い方を定義してくれるのを期待して、直接呼べなくする関数や変数にする役割を持たせることができると考えてよいでしょう。
 +
 +
 +
具体的には以下のようなプログラムになります。
 +
sample_main.cpp
 +
<syntaxhighlight lang="cpp" line start="1">
 +
#include "stdafx.h"
 +
#include "Access_Specifiers001.h"
 +
 +
int _tmain(int argc, _TCHAR* argv[])
 +
{
 +
  printf("★アクセス指定子\n");
 +
 +
  int nValue;
 +
  CAccess_Specifiers001* CAccess_Specifiers001_Instance = new CAccess_Specifiers001;
 +
 
 +
  CAccess_Specifiers001_Instance->Set_m_nValue(120);
 +
 
 +
  nValue = CAccess_Specifiers001_Instance->Get_m_nValue();
 +
 +
  printf("%d\n",nValue);
 +
 +
  //CAccess_Specifiers001_Instance->mf_m_nValue1000x();★8.protectedのメンバ関数なので呼び出せない。
 +
 +
  nValue = CAccess_Specifiers001_Instance->Get_m_nValue();
 +
 +
  printf("%d\n",nValue);
 +
 +
  printf("CIntUnit派生クラス\n");
 +
 +
  CIntUnit* CIntUnit_Instance = new CIntUnit;
 +
 +
  CIntUnit_Instance->Set_m_nValue(240);
 +
 +
  nValue = CIntUnit_Instance->Get_m_nValue();
 +
 +
  printf("%d\n",nValue);
 +
 +
  CIntUnit_Instance->mf_1000x();//★9.派生したクラスからだと呼び出しが出来る。
 +
 +
  nValue = CIntUnit_Instance->Get_m_nValue();
 +
 +
  printf("%d\n",nValue);  return 0;
 +
}
 +
</syntaxhighlight>
 +
★8.は呼び出せませんでしたが、★9.からは呼び出せます。今回のサンプルだと、なぜprotectedにしたのか明確な理由が見いだせていませんが、例えば、派生クラスではm_wcUnitを使って単位文字列の管理をしてくれることを期待しているとしたら、基本クラス設計者の期待を裏切っていることになるやもしれません。今回は自分であえて、基本クラスの理念を守らなかっただけなので、雑な派生クラスを作ったというところになります。このようにアクセス指定子には意味があるし、派生クラスに期待されていることもいくつかあるということになります。といわれても英語の文書しかない基本クラスが配布されたとして、こうやって作られた基本クラスの意図していることを、素人プログラマが理解することは、なんつうか無理があるので、使い方がわからないままにおわったり、クラスを使うことに縛られて、どうしたらいいのかわからなくなるということが起こります。こんな感じでアクセス指定子が複雑に設定されているだけで、なんとなくクラスの設計時に期待されていることがあるということがわかっていただけたら、それでこの項目で言いたかったことは伝わったように感じます。
 +
 +
 +
他にもクラスの定義で使われるいろいろなメカニズムによって基本クラスの設計者が派生クラスを生成したときの使い方で期待していることがなんなのかを予想することができるし、それを予想しなければ、うまく派生クラスを使いこなせないし、クラス自体も使いこなせないということに繋がります。もちろん、今回のサンプルのように意図していない使い方で無理やり使って、やりたいことが実現できれば、それはそれで問題ないわけです。
 +
 +
そんな感じで無理やり動かすように作成したプログラムの動作結果は以下のようになりました。見事に1000倍されています。派生したクラスは基本クラスの機能のすべてをひきついでいるということを理解しないと、sample_main.cppでのCIntUnitの使われ方について、よく意味がわからなかったかもしれませんが、アクセス制御についてなんとなく理解はしてもらえたかなと思います。
 +
 +
出力結果
 +
<syntaxhighlight lang="text">
 +
★アクセス指定子
 +
120
 +
120
 +
CIntUnit派生クラス
 +
240
 +
240000
 +
</syntaxhighlight>
 +
 +
もうひとつ、アクセス指定子に関して、補足しておかなければならないことがありまして、★5.部分のように継承をするときにもアクセス指定子を使うことができることについて触れなければなりません。★5.部分では以下のように継承したクラスの宣言を記述しました。
 +
 +
 +
'''class CIntUnit : public CAccess_Specifiers001'''{
 +
 +
};
 +
 +
このように
 +
 +
class (新規派生クラス名) : (アクセス指定子) (基本クラス名)
 +
 +
のようにして継承が定義できます。アクセス指定子は省略することもできます。省略した場合はprivateと同じになります。今回のサンプルプログラムの場合は省略するとコンパイルエラーになります。これはどういうことかというと、継承時に記述するアクセス指定子は基本クラスの中のアクセス指定を一括して書き換えて、継承(すべての関数を引き継ぐ)するために、基本クラスの中のメンバ変数やメンバ関数のすべてがpraivateのアクセスレベルになって派生クラスで利用できるようになります。せっかく引き継いでも、アクセスできないので、_tmainから利用に関しては基底クラスの変数や関数において、何も使えるものはないといってよいと思います。派生したクラスではprotectedとpublicの関数や変数は使えます。
 +
 +
 +
今回のように★5.の部分でpublicが指定されている場合は、アクセス指定子は基本クラスの内容と変わらずに使えることになります。したがった_tmain関数からも基本クラスの変数でpublicが定義されている変数や関数を呼び出すことができるためSet_m_nValueにアクセスできます。publicが指定されているからと言って格上げされることはないため、privateやprotectedの変数や関数は呼び出しできません。基本クラスで指定したアクセス指定がそのままだということです。
 +
 +
 +
★5.の部分でprotectedが指定された場合は、publicで指定されていた部分がprotectedのレベルに引き下げられ、やはり_tmain関数からは呼び出しができなくなります。派生クラスからは、publicとprotectedの両方のアクセスレベルのものへ呼び出しができます。

2015年4月27日 (月) 00:00時点における版



個人用ツール
名前空間

変種
操作
案内
ツールボックス