Cpp クラス 静的メンバ関数

提供:yonewiki

C++に戻る


本来の表記は「C++(Cpp) クラス 静的メンバ関数」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。

※このページではC++にのみ存在する機能として、記事タイトルがC++ クラス 静的メンバ関数になっています。

静的メンバ関数

静的メンバ変数と同じようなで静的メンバ関数があります。これもクラスが実体化されていなくても呼び出せるもので、静的メンバ変数は呼び出せるオブジェクト変数としての役割でしたが、ここでは呼び出し可能な関数であるということになります。実体化されていないメンバ関数は実体がないのですから、通常の静的ではないメンバ変数や関数は呼び出すことが出来ません。実体化されていないのですから、まだコンストラクタも動作していなければメンバ変数の初期化もされていないし、もし実体化されていたとしても、実体ごとに異なる値を保持していても区別して呼び出す方法、静的なメンバ関数の内部からは外部で生成されたであろう、クラスの実体を参照することは出来ないし、予測もできないので、通常のメンバ変数やメンバ関数が呼び出せないのは、ごく自然なことです。


静的なメンバ関数の関数内部の処理で、静的なメンバ変数を参照することは可能です。それって、普通の関数とどう違うの?なんかいいことあるの?って思える人もいるかもしれません。普通の関数と違う利点はほとんどありません。ただし、クラス内部にグローバルな関数を置くことで、クラスを利用するときに必要になるような関数をひとまとめにして提供することができます。いわゆるセットものです。クラスを使うなら、クラスが提供するグローバル関数も使えるよ。っていうことです。呼び出し方は、静的メンバ変数同様に名前解決スコープ演算子を利用して呼び出す必要があります。


なので、静的メンバ関数の特徴は

  • クラスとセットにできるグローバル関数が作れる。
  • クラスに関係ある処理を準備できる。
  • 同一クラス内部メンバ関数やメンバ変数は利用できない。
  • 静的メンバ関数内部の処理で静的メンバ変数や静的メンバ関数を利用できる。

ということになります。ただし、メンバ関数の処理内部でクラスの実体を生成させてあれば、その実体のメンバ関数や、メンバ変数は利用できます。あたりまえですね。メンバ関数内でint型の変数を作るのも当然できるわけですし、その他の型の変数や、構造体、クラス、メンバ関数が定義されているクラス自体の変数を利用することはできるわけです。


むしろ、そのクラス自体の変数を利用するような、静的メンバ関数が作られることの方が多いです。なぜなら、クラスとセットにするべきグローバル関数というのは、そのクラスに必要不可欠な存在である関数でありながら、実体化されなくてもいつでも使えるようにしておかなければならないようなものなのです。したがって引数にそのクラス自身の型を必要とするような関数が定義されるのは、すごく一般的です。たとえば、クラスを実体化する必要はないけど、引数だけ受け取って、そのクラスの中で扱われているメンバ変数のソートをして、メンバ変数にその順番をセットしたりする関数といったものになります。クラスに必要な関数とはそういった機能をもつ関数であることがほとんどです。


では、実際に使い方を具体的に見てみましょう。


またイチからサンプルをつくるのもなんなので、メンバ関数の記事を記述したときに使ったプログラムを改造することでサンプルにしてみたいと思います。


MemberFunc001.hファイルに以下のように書き換えます。

#pragma once
#include "membervar001.h"
class CMemberFunc001 :  public CMemberVar001
{
public:
  void mfpub_DerivationPrint(void);
  static void mfpub_XerSwap_mpub_nValue(CMemberFunc001& a,CMemberFunc001& b); //★1.静的メンバ関数
  CMemberFunc001(void);
  ~CMemberFunc001(void);
};

そして、MemberFunc001.cppに★1.部分の静的メンバ関数のプログラムを追加して


省略

void CMemberFunc001::mfpub_XerSwap_mpub_nValue(CMemberFunc001& a,CMemberFunc001& b){
  int n = a.mpub_nValue;
  a.mpub_nValue = b.mpub_nValue;
  b.mpub_nValue = n;
  CMemberVar001::m_nValue_static = 0;2.静的メンバ変数の呼び出しは出来る
}

省略

とします。静的メンバ関数内部では、クラス内の各種メンバ変数やメンバ関数の呼び出しは出来ませんが、★2.部分のように静的メンバ変数を利用することはできます。もちろん、引数でわたされた静的メンバ関数を含むクラス自体の実体に含まれるメンバ変数とメンバ関数はアロー演算子やドットによる選択演算子を使うことによって利用はできます。使えないのはクラス内部のmpub_nValueのような表記をする変数です。静的メンバ関数は実体化されなくても呼び出されるのですから、そういったクラス内部を指し示すような変数は使えません。


ちなみにmfpub_XerSwap_mpub_nValueという関数はCMemberFunc001クラス型の参照型変数2つを引数として、2つのクラスの実体に含まれるメンバ変数mpub_nValueの値を受け取った二つのクラスの中で交換するという処理をしています。int型のメンバ変数の値を交換するだけなので、よくみかける交換処理が記述されています。


それでメインプログラムは以下のように書き換えます。 sample_main.cpp

#include "stdafx.h"
#include "MemberVar001.h"
#include "MemberFunc001.h"

int _tmain(int argc, _TCHAR* argv[])
{
  CMemberFunc001*  CMemberFunc001_Instance = new  CMemberFunc001;
  CMemberFunc001*  CMemberFunc002_Instance = new  CMemberFunc001;

  CMemberFunc001_Instance->m_nValue_static = 1;//★4.実体変数からメンバ変数を呼び出し。
  CMemberFunc001_Instance->mpub_nValue = 1000;
  CMemberFunc002_Instance->mpub_nValue = 2000;

  printf("%d %d %d\n",CMemberVar001::m_nValue_static,CMemberFunc001_Instance->mpub_nValue,CMemberFunc002_Instance->mpub_nValue);

  CMemberFunc001::mfpub_XerSwap_mpub_nValue(*CMemberFunc001_Instance,*CMemberFunc002_Instance);//★3.静的メンバ関数呼び出し

  printf("%d %d %d\n",CMemberVar001::m_nValue_static,CMemberFunc001_Instance->mpub_nValue,CMemberFunc002_Instance->mpub_nValue);

  return 0;
}

そうすると、3.部分のように静的メンバ関数を呼び出すことができて、特に実体化されていなくても関数を名前解決スコープ演算子を使うことで、変数名、オブジェクト名、インスタンス(実体)名を使って、ドットによる選択演算子やアロー演算子を使わずに静的なメンバ関数を呼び出すことができます。


実は、変数名やオブジェクト名、インスタンス名を使っても静的メンバ関数を呼び出すことはできます。どのような方法で呼び出しても構わないです。ちなみに★4.部分では、静的メンバ変数の呼び出しをインスタンス(実体)名を使って、呼び出ししています。


その結果、出力の結果は以下のようになります。

出力結果

■CMemberVar001コンストラクタ mf_Printプライベート関数アクセス可能
CMemberVar001 プライベート メンバ関数
mpub_nValue=-842150451,mpro_nValue=-842150451,m_nValue=      2000

CMemberVar001 mf_Print関数から呼び出し
★CMemberVar001 プロテクト  mfpub_Print2関数
★CMemberVar001 パブリック  mfpub_Print2関数

■CMemberVar001コンストラクタ 処理終了
■CMemberVar001コンストラクタ mf_Printプライベート関数アクセス可能
CMemberVar001 プライベート メンバ関数
mpub_nValue=-842150451,mpro_nValue=-842150451,m_nValue=      2000

CMemberVar001 mf_Print関数から呼び出し
★CMemberVar001 プロテクト  mfpub_Print2関数
★CMemberVar001 パブリック  mfpub_Print2関数

■CMemberVar001コンストラクタ 処理終了
1 1000 2000
0 2000 1000

といった出力になります。


このようにクラスに関係のある、変数の入れ替え処理として静的なメンバ関数を定義したことになり、クラスの中に含めて、記述することが非常に自然な振る舞いであることがわかっていただけたと思います。たぶん…


静的メンバ関数とはこういうものです。ちなみに関数名にXerSwapとしましたが、XにはTransという意味がありまして、Transfer Xferで変換という意味があります。Trasn自体はその向こうにというような意味があります。またぐというような意味あいから交差を意味するXがしばしば代用される慣習がうまれたものと思われます。Xerだと略しすぎなので本来はXferとして表現すべきなのかもしれません。他にもXにはいろいろな使い方がされます。そのあたりの詳細な解説はWikipediaのXの記事にゆずりたいと思います。交換変換か…


C++に戻る