Cpp クラス 抽象クラス

提供:yonewiki
2022年9月26日 (月) 11:30時点におけるYo-net (トーク | 投稿記録)による版 (ページの作成:「C++に戻る <table class="mbox-small" style="border:1px solid #aaa; background-color:#f9f9f9; width:22em;" id="RealTitleBanner"> <tr> <td style="width:1px;"></td> <td class="mbox-text plainlist" style="">本来の表記は「<b><span id="RealTitle" style="font-size:large;">C++(Cpp) クラス 抽象クラス</span></b>」です。この記事に付けられた題名は{{記事名の制約}}から不正確なものとなってい…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)

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++に戻る