[C/C++]継承実例、カプセル化して平均と標準偏差を求めよう!

スポンサーリンク

>

妹「お兄ちゃん平均値と標準偏差を求めるプログラムを教えて」
兄「計算は以前やったから。じゃあ今日はC++でソースを書いて解説してみるね」
妹「でも、C++だと面倒じゃないの?」
兄「そうでもないよ、慣れるとC/C++はとても使いやすい言語なんだよね……はい、Addメソッドで値を追加してCalcを呼んだら答えがreturn されるプログラムができたよ」

妹「なんか短いね。もしかして.Netで書くよりも短いかも……。でも、あれ、お兄ちゃん……Add関数の中のpush_back関数ってどこにあるの?これじゃあリンクできないんじゃないの?」
兄「sumVectの中では持ってないよ。それは継承元のstd::vectorが持っている関数なんだ。配列を管理してくれる。動的配列を作って破棄してってやるとそっちがメインになりそうだから、std::vectorそのまま、詳しくはMSDN解説のvectorクラスでも見れば解るよって言いたかったんだよね」
妹「配列を作ったり、管理したりするの面倒だから……こんな便利なクラスがあったんだね!でもprivateで継承しているのは何でなの?」


兄「使う側が迷わないようにカプセル化してあるんだよ」
妹「カプセル化?」
兄「例えば、妹はこのクラスを使う時に、AddとCalcしか無かったら……Addでダブル型を追加してCalcすれば計算されるって直感的に解ると思う」
妹「うん……分かりやすいね」

兄「でも、これがもし継承元をpublicで継承していたら、上の図のようになる。こうなると、どのメソッドで配列に入れられるかって事……つまり妹がvectorの知識を持ってないと使い方が解らなくなってしまう恐れがあるよね。だからカプセル化して隠すんだ」
妹「短いソースコードの中にも工夫があるんだねっ」

//*** youwaka.net (pσ_σ)q ***  
#include <iostream>
#include "vector"
//*** youwaka.net (pσ_σ)q ***  
using namespace std;

class sumVect:private vector<double>
{
public:
    sumVect() { memset(&this->Result, 0x00, sizeof(this->Result)); }
    ~sumVect() { this->clear(); }
    //計算結果構造体
    struct sumVectResult { double num, sum, ave, avepow2, sumpow2, stdev; };

    void Add(double p) { this->push_back(p); }
    void Clear() { this->clear(); }

    sumVectResult* Calculate()    //計算
    {
        memset(&this->Result, 0x00, sizeof(this->Result));
        this->Result.num = this->size();
        for (unsigned short i = 0; i < this->Result.num; i++){
            this->Result.sum += this->at(i);
            this->Result.sumpow2 += this->at(i) * this->at(i);
        }
        this->Result.ave = this->Result.sum / this->Result.num;
        this->Result.avepow2 = this->Result.sumpow2  / this->Result.num;
        this->Result.stdev = sqrt(Result.avepow2 - Result.ave * Result.ave);
        return &this->Result;
    }
private:
    sumVectResult Result;
};
int main()
{
    sumVect p; p.Add(150.27), p.Add(160.13), p.Add(170.82), p.Add(180.42), p.Add(145.62), p.Add(182.62);
    sumVect::sumVectResult *ans =  p.Calculate();
    printf("平均身長=%f,標準偏差%f\n", ans->ave, ans->stdev);
    //検算
    p.Clear();
    p.Add(1), p.Add(2), p.Add(3), p.Add(4), p.Add(5);printf("%f 検算用標準偏差 \n", p.Calculate()->stdev);
    p.
    return 0;
}