Cpp クラス 抽象クラス
C++に戻る
本来の表記は「C++(Cpp) クラス 抽象クラス」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。 |
※このページではC++にのみ存在する機能として、記事タイトルがC++ クラス 抽象クラスになっています。
クラス 抽象クラス
抽象クラスは、単体ではもう機能しないような基底クラスになってしまう手法で、先の記事で説明した仮想関数を使う時に基底クラスにはプログラムの実体を持たない方法です。Cpp クラス 仮想関数で使っていたプログラムでは基底クラスは2箇所をvirtualキーワードで仮想関数にしていましたが、そのうちのmfVirtual_vDispValue()に変更して、基底クラスだったCBaseInheritanceを抽象クラスにしたいと思います。
まずは元々の基底クラスはこうだったという例を示します。
cpp (基底クラス BaseInheritance.h)
#ifndef __BASEINHERITANCE_H_YONET__
#define __BASEINHERITANCE_H_YONET__
#if _MSC_VER > 1000
#pragma once
#endif
class CBaseInheritance {
protected:
int m_iBaseMoney = 0;
int m_iBaseMonth = 0;
int m_iMoney = 0;
int mf_iBaseSumMoney();
public:
CBaseInheritance();
CBaseInheritance(int iArgBaseMoney, int iArgBaseMonth);
virtual ~CBaseInheritance();
virtual void mfVirtual_vDispValue();
void mf_vBaseDispValue();
};
#endif
基底クラスの仮想関数がありましたが、基本料金が0円だったかどうかも、必ず知りたいとしたら、オプションが0円だったということも含めて呼びだされたいため、このクラスがそのまま使われるとまずいという考え方もできます。基底クラスが直接呼ばれたら、オプション料金の設定忘れということになってしまいます。ならば、基本料金を返却表示してしまう部分は派生クラスでプログラムされて、かつ基底クラスではプログラムを持たない形式にすると良いと考えることが出来ます。こういった、基底クラスの関数が派生クラスに全投げする状態の関数を純粋仮想関数と言います。
純粋仮想関数として定義するのも仮想関数がvirtualというキーワードを付けるだけだったの同様に簡単で、仮想関数を0で初期化することで、宣言だけで、プログラムを持つ必要がなくなります。具体的には以下のようになります。
cpp (基底クラス BaseInheritance.h)
#ifndef __BASEINHERITANCE_H_YONET__
#define __BASEINHERITANCE_H_YONET__
#if _MSC_VER > 1000
#pragma once
#endif
class CBaseInheritance {
protected:
int m_iBaseMoney = 0;
int m_iBaseMonth = 0;
int m_iMoney = 0;
int mf_iBaseSumMoney();
void mf_vBaseDispValue();
public:
CBaseInheritance();
CBaseInheritance(int iArgBaseMoney, int iArgBaseMonth);
virtual ~CBaseInheritance();
virtual void mfVirtual_vDispValue() = 0;
};
#endif
と118行目のように
virtual void mfVirtual_vDispValue() = 0;
とすることで、基底クラスに純粋仮想関数が定義され、抽象クラスになったと言えます。本来の意味としては、派生クラスに全部任せるから、基底クラスを直接利用されないようにmf_vBaseDispValue()はprotectedに移動させておきました。サンプルなので、そこまでする必要もないし、あんまり有意義でもないですが、カッコだけはつけておきました。
それだけではまずくて、プログラム部も以下のように、mfVirtual_vDispValue()のプログラム部分を消す必要があります。
cpp (基底クラス BaseInheritance.cpp)
#include "pch.h"
#include "BaseInheritance.h"
CBaseInheritance::CBaseInheritance() {
printf("Constructor:CBaseInheritance()\n");
}
CBaseInheritance::CBaseInheritance(int iArgBaseMoney, int iArgBaseMonth)
:m_iBaseMoney(iArgBaseMoney)
,m_iBaseMonth(iArgBaseMonth)
,m_iMoney(0) {
printf("Constructor:CBaseInheritance(int,int)\n");
}
CBaseInheritance::~CBaseInheritance() {
printf("Destructor:~CBaseInheritance()\n");
}
int CBaseInheritance::mf_iBaseSumMoney() {
m_iMoney = m_iBaseMoney * m_iBaseMonth;
return m_iMoney;
}
void CBaseInheritance::mf_vBaseDispValue() {
int iSumMoney = m_iBaseMoney * m_iBaseMonth;
printf("BaseMoney=%d, total=%d\n", iSumMoney, m_iMoney);
}
このように、まるまるプログラム部分を削りました。このサンプルではプロジェクトからCDeriveArrInheritanceとCDeriveDiscountInheritanceを除外しています。
で動かすと
実行結果
Constructor:CBaseInheritance(int,int)
Constructor:CDriveInheritance(int,int,int)
BaseMoney=22800, OptionMoney=600 total=23400
Constructor:CBaseInheritance(int,int)
Constructor:CDriveInheritance(int,int,int)
BaseMoney=22800, OptionMoney=600 total=23400
Destructor:~CBaseInheritance()
Destructor:~CDriveInheritance()
Destructor:~CBaseInheritance()
と問題なく動作します。
C++に戻る