Cpp クラス 継承 デストラクタ 新しいページはコチラ

提供: yonewiki
移動: 案内, 検索
(ページの作成:「C++に戻る <table class="mbox-small" style="border:1px solid #aaa; background-color:#f9f9f9; width:22em;" id="RealTitleBanner"> <tr>...」)
 
 
5行: 5行:
 
<tr>
 
<tr>
 
<td style="width:1px;"></td>
 
<td style="width:1px;"></td>
<td class="mbox-text plainlist" style="">本来の表記は「<b><span id="RealTitle" style="font-size:large;">C++ クラス 継承 デストラクタ</span></b>」です。この記事に付けられた題名は{{記事名の制約}}から不正確なものとなっています。</td>
+
<td class="mbox-text plainlist" style="">本来の表記は「<b><span id="RealTitle" style="font-size:large;">C++(Cpp) クラス 継承 デストラクタ</span></b>」です。この記事に付けられた題名は{{記事名の制約}}から不正確なものとなっています。</td>
 
</tr>
 
</tr>
 
</table>
 
</table>
11行: 11行:
 
<br />
 
<br />
 
== '''クラス 継承 デストラクタ''' ==
 
== '''クラス 継承 デストラクタ''' ==
 +
 継承におけるコンストラクタの挙動は先の[[Cpp クラス 継承]]でも簡単に示した通りで、デストラクタまで踏まえると呼び出される順番は派生クラスのオブジェクト生成後、まずは基底クラスのコンストラクタが呼ばれて、次に派生クラスのコンストラクタが呼ばれます。そして派生クラスのオブジェクト消滅の寸前で、派生クラスのデストラクタが呼ばれて、次に基底クラスのデストラクタが呼ばれ、そして、オブジェクトが消滅します。
 +
 +
 +
 この時、派生クラスに引数がある場合でも、基底クラスでは引数を取らないコンストラクタが呼ばれます。そして基底クラスに引数付きのコンストラクタを作った場合は、引数を取らないデフォルトコンストラクタは何も処理をしないとしても明記しないと継承時に派生クラスは独自の引数のコンストラクタを持つことが出来ないのでした。
 +
 +
 +
 じゃぁもう説明すること無いんじゃね?
 +
 +
 +
 と、継承の記事からやってきた人は思うかもしれない、でも、継承 アップキャストの記事から来た人は最後に提示された問題の解決をしなければならないことを知っているかもしれません。詳しくは[[Cpp クラス 継承 アップキャスト]]を参照して下さい。アップキャストのような使い方をすると、基底のクラスが動的に生成されつつも、アップキャストで基底クラスが利用するクラスを決定するようなプログラムで派生クラスでも動的に生成する変数やクラスがあった場合、派生クラスで、デストラクタを準備したとしても、基底クラスが消滅した場合には派生クラスのデストラクタは呼ばれません。基底クラスのデストラクタが派生クラスのデストラクトがあることを知らないからです。派生クラスのデストラクタがあると知らせるにはデストラクタを仮想関数にする必要があります。オーバライドされてると教え込むことで、派生クラスのデストラクタが動きます。
 +
 +
 +
 [[Cpp クラス 継承 アップキャスト]]で示したサンプルプログラムの基底クラスを以下のようにします。
 +
 +
<span style="color: #ffffff; background-color: #555555; padding: 0px 5px 0px 5px; display: inline-block;">cpp <span>(</span>基底クラス BaseInheritance.h<span>)</span><!-- padding 上 右 下 左-->
 +
<syntaxhighlight2 lang="cpp" line>
 +
#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();
 +
    void mf_vDispValue();
 +
    void mf_vBaseDispValue();
 +
};
 +
#endif
 +
</syntaxhighlight2>
 +
 +
 16行目の
 +
 +
<syntaxhighlight2 lang="cpp">
 +
virtual ~CBaseInheritance();
 +
</syntaxhighlight2>
 +
 これだけで、基底クラスが消滅したときにアップキャストされた基底クラスが派生クラスのデストラクタを保持することになります。つまり派生クラスのデストラクタが動く可能性が出てきました。しかし、今回作ったメイン関数では、ポリモーフィズムで形態を変えるごとに基底クラスが消滅しないため、1回目の派生クラスからのアップキャスト生成と2回目のアップキャスト生成に対しては消滅処理がされないため、派生クラスのデストラクタは呼ばれません。基底クラスのデストラクタも呼ばれません。
 +
 +
 +
 ですから、上記変更だけを適用した状態では、動作結果は以下のようになります。
 +
 +
<span style="color: #ffffff; background-color: #555555; padding: 0px 5px 0px 5px; display: inline-block;">実行結果<!-- padding 上 右 下 左-->
 +
<syntaxhighlight2 lang="text" line start=100>
 +
Constructor:CBaseInheritance(int,int)
 +
Constructor:CDriveInheritance(int,int)
 +
BaseMoney=34800, total=35700
 +
Constructor:CBaseInheritance(int,int)
 +
Constructer:CDeriveArrInheritance(int,int,int*,int)
 +
BaseMoney=34800, total=36520
 +
Constructor:CBaseInheritance(int,int)
 +
Constructer:CDeriveDiscountInheritance(int,int,double)
 +
BaseMoney=46800, total=23400
 +
Destructer:~CDeriveDiscountInheritance()
 +
Destructor:~CBaseInheritance()
 +
</syntaxhighlight2>
 +
 +
 それで、メイン関数で形態を変える都度、消滅する処理をいれると、以下のようになります。
 +
 +
<span style="color: #ffffff; background-color: #555555; padding: 0px 5px 0px 5px; display: inline-block;">cpp <span>(</span>メイン関数 InheritanceMain.cpp<span>)</span><!-- padding 上 右 下 左-->
 +
<syntaxhighlight2 lang="cpp" line start=200>
 +
#include "pch.h"
 +
#include "BaseInheritance.h"
 +
#include "DeriveInheritance.h"
 +
#include "DeriveArrInheritance.h"
 +
#include "DeriveDiscountInheritance.h"
 +
 +
CBaseInheritance* pCBaseInheritanceUpcastF(int iSelectDerive) {
 +
    int piOptionUpcastArr[] = { 800, 200, 500, 220 };
 +
    int iSize = (int)(sizeof piOptionUpcastArr / sizeof(*piOptionUpcastArr));
 +
    switch (iSelectDerive) {
 +
        case 1:
 +
            return new CDeriveInheritance(2900, 12);
 +
        case 2:
 +
            return new CDeriveArrInheritance(2900, 12, piOptionUpcastArr, iSize);
 +
        default:
 +
            return new CDeriveDiscountInheritance(3900, 12, 0.5);
 +
    }
 +
};
 +
 +
int main() {
 +
 +
    CBaseInheritance* pCBaseInheritanceUpcast;
 +
    pCBaseInheritanceUpcast = pCBaseInheritanceUpcastF(1);
 +
    pCBaseInheritanceUpcast->mf_vDispValue();
 +
    delete pCBaseInheritanceUpcast;
 +
 +
    pCBaseInheritanceUpcast = pCBaseInheritanceUpcastF(2);
 +
    pCBaseInheritanceUpcast->mf_vDispValue();
 +
    delete pCBaseInheritanceUpcast;
 +
 +
    pCBaseInheritanceUpcast = pCBaseInheritanceUpcastF(3);
 +
    pCBaseInheritanceUpcast->mf_vDispValue();
 +
    delete pCBaseInheritanceUpcast;
 +
 +
    return 0;
 +
 +
}
 +
</syntaxhighlight2>
 +
 +
 これなら、なんとなく思い描いたとおりの動作になります。
 +
 +
<span style="color: #ffffff; background-color: #555555; padding: 0px 5px 0px 5px; display: inline-block;">実行結果<!-- padding 上 右 下 左-->
 +
<syntaxhighlight2 lang="text" line start=300>
 +
Constructor:CBaseInheritance(int,int)
 +
Constructor:CDriveInheritance(int,int)
 +
BaseMoney=34800, total=35700
 +
Destructer:~CDeriveInheritance()
 +
Destructor:~CBaseInheritance()
 +
Constructor:CBaseInheritance(int,int)
 +
Constructer:CDeriveArrInheritance(int,int,int*,int)
 +
BaseMoney=34800, total=36520
 +
Destructer:~CDeriveArrInheritance()
 +
Destructor:~CBaseInheritance()
 +
Constructor:CBaseInheritance(int,int)
 +
Constructer:CDeriveDiscountInheritance(int,int,double)
 +
BaseMoney=46800, total=23400
 +
Destructer:~CDeriveDiscountInheritance()
 +
Destructor:~CBaseInheritance()
 +
</syntaxhighlight2>
 +
 +
 という感じで、きちんとそれぞれの派生クラスのデストラクタが動くようになります。よくクラスのデストラクタにはvirtualを付けとけ、というようなことを言う、なんでもvirtual ~xxxデストラクタ主義を唱える人がいますが、自分はアップキャストで使うクラスだけに付ければよいと思います。そんなアップキャストするかどうかも意識していない基底クラスを利用すれば、デストラクタがどこではたらくかを意識していないということになるので、雑なプログラムになってしまいます。ちゃんと管理した方が良いと思います。設計図でしっかりと管理してほしいな。なんでもvirtualでもいいですけど。不要なデストラクタが省略できなくなるよ。
 +
 +
 +
 それってわかりにくくないかな。
 +
 +
 +
 好きなようにしてもらえればいいですけど。
  
  
 
[[C PlusPlus#C++からの技術|C++]]に戻る
 
[[C PlusPlus#C++からの技術|C++]]に戻る

2021年2月6日 (土) 00:00時点における最新版



個人用ツール
名前空間

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