2014年1月29日水曜日

C++ デストラクタを仮想関数にする


いつものPCが不調につき。

開発者の手助けとなるツールにEclipseという

ものがあります。

IDE(Integrated Development Environment)

なのでデバッグもできてしまいます。




GUIでの簡単な操作、しかも無料で使えるというのは本当に素晴らしいですね!

さて、本題に入ります(^_^;)

継承する可能性のあるクラスのデストラクタは、仮想関数にしてください。

今、基底クラスのポインタが、その基底クラスから派生したクラスの

オブジェクトを指している場合を考えてみます。

基底クラスのデストラクタが仮想関数でない場合、基底クラスのポインタに対して

delete を実行すると、なんと派生クラスのデストラクタが呼ばれないのです(>_<)

したがって、派生クラスのデストラクタ内でメモリの解放をしているような場合、

基底クラスのポインタから delete を実行しても、そのメモリが解放されないという

困った現象が起きてしまいます(-_-;)

とある実行結果
# ./test
I'm Vegetable::SetPrice()
Price = I'm Vegetable::GetPrice()
398
I'm ~Food()

これを回避するためには、次のように基底クラスのデストラクタを

仮想関数にしておくことで、派生クラスのデストラクタが呼ばれるようになります。

class Food {
public:
    Food();
    virtual ~Food();    //デストラクタを仮想関数にしています
        :

とある実行結果2
# ./test
I'm Vegetable::SetPrice()
Price = I'm Vegetable::GetPrice()
I'm ~Vegetable()
I'm ~Food()

メモリリークが原因で、突然プログラムが落ちてしまうという問題は、

何が原因かを特定するまで難航することがあります(?_?)

こだわりを持って、品質のいいソフトウェア開発ができるようにしたいものです。

こんな使い方はしなさそうな、今回の状況を試すためのサンプル
include <iostream>

using namespace std;

class Food
{
public:
    //~Food();      こちらでは派生クラスのデストラクタが呼ばれません
    virtual ~Food();      //こちらは実行結果2のほうになります
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

class Vegetable : public Food
{
public:
    ~Vegetable();
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
    int *m_ptr;
};

Food::~Food()
{
    cout << "I'm ~Food()" << endl;
}

oid Food::SetPrice(int price)
{
    cout << "I'm Food::SetPrice()" << endl;
    m_price = price;
}

int Food::GetPrice(void)
{
    cout << "I'm Food::GetPrice()" << endl;
    return m_price;
}

Vegetable::~Vegetable()
{
    cout << "I'm ~Vegetable()" << endl;
    if (m_ptr != NULL) { delete m_ptr; m_ptr = NULL; }
}

nt Vegetable::GetPrice(void)
{
    cout << "I'm Vegetable::GetPrice()" << endl;
    return m_price;
}

int main(void)
{
    Vegetable *pmyVegetable = new Vegetable;
    Food *pmyFood = pmyVegetable;

    pmyVegetable->SetPrice(398);
    cout << "Price = " << pmyVegetable->GetPrice() << endl;

    delete pmyFood;

    return 0;
}


今日の名言
苦境に立って万事休した時には、できることがあれば、それをやる。できることが
なければ、あとは忘れるだけだ。私は未来について決して心配しない。未来に
どんなことが起きるかを予想できる人などいないからだ。未来に影響を及ぼす力は
実にたくさんある!それらの力を動かすものが何であるのか誰も知らないし、
その力自体も理解できない。なのに、どうして悩むのだ。
                                K・T・ケラー

人を憎むのは、ネズミ一匹追い出すために、家全体を焼き払うようなものだ。
                         ハリー・エマーソン・フォデスディック

私は一文無しになっても悩みはしないだろう。悩んだところで何の益もないからだ。
私は最善を尽くして、あとの結果は神におまかせする。
                                J・C・ペニー

2014年1月23日木曜日

C++ オブジェクトの配列を初期化




今回はオブジェクトの配列を初期化する方法
についての紹介になります(^^)

通常の変数と同様に、もちろんオブジェクトも
配列にすることができます。






初期化する場合は以下のようになります。

//まずはDateクラスの定義
class Date
{
public:
    Date(int year, int month, int day)
    {
        m_year = year;
        m_month = month;
        m_day = day;
    }
private:
    int m_year;
    int m_month;
    int m_day;
};

int main(void)
{
    //そしてDateクラスの2つのオブジェクトを宣言と同時に初期化
    Date UseByDate[2] = { Date(2014, 1, 13), Date(2014, 2, 14) };
        :

この場合は、Dateクラスの2つのオブジェクトが引数を3つ取る
コンストラクタで初期化されます(^-^)

初期化のバリエーションについて
オブジェクトの配列の初期化では、要素の途中まで
初期化するということもできます。

Date UseByDate[31] = { Date(2014, 1, 13), Date(2014, 2, 14) };

この場合、要素は31個ありますが、最初の2つだけが引数を3つ取る
コンストラクタが呼び出されます。
そして、残りの29個については、引数のないコンストラクタが呼び出されます。

また、コンストラクタの引数が一つだけの時は、引数の内容だけを
記述することもできます。

   :
    Date(const char *datestr)
    {
        cout << datestr << endl;
    }
        :
int main(void)
{
    //もちろん従来のように書いても構いませんし
    Date UseByDate1[2] = { Date("2014/03/15"), Date("2014/04/16") };  
    //引数の内容だけを記述してみたってのもありです
    Date UseByDate2[2] = { "2014/03/15", "2014/04/16" };
        :

いずれにしても、同じ内容で初期化されているというのが
分かるかと思います(^^) 

今日の名言
一つ一つの問題の本質を正しくつかめ。仕事を分割して
適当に時間割りせよ。
                           ベンジャミン・フランクリン

人生の全体ばかりに気を取られて思い悩んではいけない。まだ自分の手元に
来るかどうかわからない重荷の数と性質を、一目で読み取りとろうとするな。
むしろ問題が起こるたびに、「この仕事の手に負えない個所はどこだろか」と
自問するのだ。この問いに正直に答えれば、自分でも赤面したくなるだろう!
次に思い出すべきことは、過去も未来も自分を押し潰すことはできない、自分を
押しつぶせるのは現在だけだ、ということである。その現在ですら、もし適当に
分割してそれぞれの大きさの範囲を決めたうえで、自分に問い直せば、
取るになりぬものとなる。
                           マルクス・アウレリウス

2014年1月18日土曜日

C++ オブジェクトをメンバに持つ





今回はオブジェクトをメンバに持つクラスの
説明です。


通常の変数や関数と同様に、オブジェクトを
クラスのメンバにすることもできます。(^^)




オブジェクトをメンバにして新しいクラスを作ることは、よくあります。
例えば以下のようになります。

//Dateクラスの定義
class Date
{
public:
    Date(int year, int month, int day)
    {
        m_year = year;
        m_month = month;
        m_day = day;
    }
private:
    int m_year;
    int m_month;
    int m_day;
};

class Food
{
public:
    static double sm_tax;
    static void SetTax(double tax){
        sm_tax = tax;
    }
    void SetPrice(int price);
    int GetPrice(void);
private:
    Date BestBeforeDate;  //DateクラスのBestBeforeDateオブジェクト
    int m_price;
};

そのままFoodクラスの中に、Dateオブジェクトがあるイメージです(^^;)

メンバにしたオブジェクトを初期化するには
先のようにメンバにしたオブジェクトの初期化は、コンストラクタで行います。
但し、コンストラクタの中ではなく、初期化リストという部分で初期化します。

//BestBeforeDateオブジェクトの初期化と変数m_priceの初期化
Food()
:BestBeforeDate(2014, 1, 13), m_price(105)
{}

初期化リストの形式は、「:(コロン)」に続けて初期化するためのリストを
書いていきます。複数ある場合は、「,(カンマ)」で区切ります(^-^)

このように、オブジェクトだけでなく int型やdouble型 などの
メンバ変数もここで初期化することができます。

初期化されるときの順番は、メンバにしたオブジェクトの後に
コンストラクタの内容が実行されます。

class Date
{
public:
    Date(int year, int month, int day)
    {
        m_year = year;
        m_month = month;
        m_day = day;
        cout << "I'm Date Object." << endl;
    }
    :
class Food
{
public:
    Food()
    :BestBeforeDate(2014, 1, 13), m_price(105)
    {
        cout << "I'm Food Object." << endl;
    }
    :

こんな感じに実験してみると、確かにDateの方が先に実行されて
いるのがわかります。

# ./test
I'm Date Object.
I'm Food Object.

ただ、初期化リストはたまにしか使わないと、ついつい書式を忘れて
Google先生に聞くことになりますね...(*´Д`)

今日の名言
些細なことをとやかく言うな。取るにも足りぬこと - 人生のシロアリ - に
自分の幸福を食いつぶされるな。
                               デール・カーネギー

やるべきことは、遠くにぼんやり見えるものを見ることではなく、
手直にはっきり見えるものを行うことである。
                               トーマス・カーライル

もはや手の施しようのない事態になったら、事態の成り行きに任せるだけだ。
                               ヘンリー・フォード

「記録を調べてみよう」そして、こう自問するのだ。「平均値の法則によると、
不安の種になっている事柄が実際に起こる確率はどのくらいだろうか?」
                               デール・カーネギー

一度決断を下し、後は実行あるのみとなったら、その結果に対する責任や
心配を完全に捨て去ろう。
                               ウィリアム・ジェイムズ

2014年1月9日木曜日

C++  静的メンバ関数




静的メンバ関数とは、静的メンバ変数にだけ
アクセスするための関数です。


メンバ関数にstaticを付けて宣言すると、
静的メンバ関数になります(^^)






class Food
{
public:
    static double sm_tax;
    static void SetTax(double tax){  //staticを付ける
        sm_tax = tax;

    }
        :

なお、静的メンバ関数から同じオブジェクト内のメンバを利用するには
メンバにstaticをつけなければなりません。
つまり、static以外のメンバにアクセスはできないということです(^^;)

静的メンバ関数の呼び出しかた
静的メンバ関数なので、静的メンバ変数と同様にオブジェクトを生成しなくても
呼び出すことができます。

nt main(void)
{
    Food::SetTax(1.05);  //スコープ解決演算子を使用
   :

また、オブジェクトを生成した場合は、通常のメンバ変数を呼び出すのと同じように
呼び出すことができます(^^)
   :
    Food myFood;
    myFood.SetPrice(1500);
       :

スコープ解決演算子を使って呼び出すのが分かりやすくておススメですね。

では、例によってプログラム全体を。
#include <iostream>

using namespace std;

class Food
{
public:
    static double sm_tax;
    static void SetTax(double tax){  //staticを付ける
        sm_tax = tax;
    }
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

double Food::sm_tax = 0;

void Food::SetPrice(int price)
{
    m_price = price;
}

int Food::GetPrice(void)
{
    return m_price;
}

int main(void)
{
    Food::SetTax(1.05);  //スコープ解決演算子を使用

    Food myFood;

    myFood.SetPrice(1500);
    cout << "Food Price[1500](in tax 5%) = " << myFood.GetPrice() * myFood.sm_tax << endl;

    //.(ピリオド)を使ってアクセス
    myFood.SetTax(1.08);  //増税して8%になってしまった...
    cout << "Food Price[1500](in tax 8%) = " << myFood.GetPrice() * myFood.sm_tax << endl;

    return 0;
}

実行結果
# ./test
Food Price[1500](in tax 5%) = 1575
Food Price[1500](in tax 8%) = 1620

新年あけまして、増税が近づいてきました...(-_-;)

今日の名言
コロラド州ロングズ・ピークの山腹に一本の巨木の残骸がある。博物学者によれば、
樹齢四百年の木だという。その木は、コロンブスがサン・サルバドルに上陸した頃は
苗木であったし、清教徒たちがプリマスに定住した頃には若木に成長していた。
その木は長い生涯の間に十四回も落雷に見舞われ、四世紀間には数えきれないほど
多くの雪崩や暴風雨がその木を襲った。その木はひたすら生き抜いた。しかしながら、
最後はカブトムシの大群が押し寄せ、その巨木を地上に倒してしまった。虫たちは
樹皮を破って侵入し、少しずつではあるが間断のない攻撃によって、徐々に巨木の
生命力を破壊してしまったのである。長い歳月に耐え、雷鳴を物ともせず、嵐にも
屈しなかった森の巨木が、人間の指でひねりつぶされてしまう小さな虫たちのために、
ついに倒されてしまったのだ。
                               ハリー・エマーソン・フォスディック

2014年1月7日火曜日

C++ 静的メンバ変数




今回は静的メンバ変数の話です。

これは、メンバ変数に static を付けるだけで

「静的メンバ変数」になります。

静的メンバ変数とは、複数のオブジェクトで
共通のメモリ領域を持つメンバ変数のことです。



一つのクラスから精製したオブジェクトの静的メンバ変数は、
値が共通になります。

どのオブジェクトでも共通なデータは static にできますので、
メモリの節約に役立ちます(^^)

class Food
{
public:
    static double sm_tax;    //staticを付ける
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

静的メンバ変数の初期化について
静的メンバ変数の初期化は cppファイルの中で一度だけ行います。
コンストラクタで初期化しないよう注意してください。(^^;)
オブジェクトの生成ごとに何度も初期化されてしまいますので(*´Д`)

静的メンバ変数のアクセスについて
publicな静的メンバ変数の場合、オブジェクトを生成しなくても
スコープ解決演算子を使ってアクセスすることができます。
また、オブジェクトを生成している場合は、「.(ピリオド)」を使って
通常のメンバ変数のようにアクセスすることもできます。

int main(void)
{
    Food::sm_tax = 1.05;  //初期化
    Food myFood;
       :
    myFood.sm_tax = 1.08;  //増税8%
        :

では、サンプルプログラム全体です。

#include <iostream>
#include <string.h>

using namespace std;

class Food
{
public:
    static double sm_tax;    //staticを付ける
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

double Food::sm_tax = 1.05;

void Food::SetPrice(int price)
{
    m_price = price;
}

int Food::GetPrice(void)
{
    return m_price;
}

int main(void)
{
    Food::sm_tax = 1.05;  //初期化

    Food myFood;

    myFood.SetPrice(1500);
    cout << "Food Price1 = " << myFood.GetPrice() * Food::sm_tax << endl;

    myFood.sm_tax = 1.08;  //増税8%
    cout << "Food Price2 = " << myFood.GetPrice() * Food::sm_tax << endl;

    return 0;
}

実行結果
# ./test
Food Price1 = 1575
Food Price2 = 1620

うむむ、消費税8%だと 1500円のモノを買った時の値段は
割高感満点ですね(-_-;)

今日の名言
幸福への道はただ一つしかない。それは意志の力でどうにもならない物事は
悩んだりしないことである。
                           エピクテトス

随分前のことだが、ある日私は不安と幻滅をおぼえ、私の一生は自分では
どうにもならない力で操られているように思われた。ある朝ふと新約聖書を
開いてみると、次の一節が目に止まった。「我を地上に送りたまいし者、常に
我とともにあり-父なる神は我を見捨てたまわず」私の人生はその瞬間から
一変した。それ以来、私にはあらゆることが永遠に違ったものとなった。
一日として、この一節を繰り返さない日はなかった。近年、多くの人々が
私のもとを訪れて助言を求めるが、私はいつも別れ際にこの励ましの言葉を
伝えている。この一節に目を止めて以来、私はこの言葉によって生きてきた。
私はこの一節とともに歩み、この中に平和と力とを見出している。私にとっては、
これこそ宗教の真髄である。この言葉は、人生を価値あるものにするすべての
物の基盤となっている。何物にも代えがたい私の人生の教科書である。
                           ジョセフ・R・サイズー

2014年1月5日日曜日

C++ 静的メンバ



今回は、C++のクラスの特徴についての
話になります。(^^)

C++では、クラスに静的メンバ変数というものが
定義できます。




通常クラスからオブジェクトを生成すると、そのオブジェクトごとにメンバ変数用の

メモリが割り当てられます。

しかし、静的メンバ変数の場合、クラスで共通のメモリ領域が割り当てられます。

そのため、各オブジェクトで同じ値を共有するような場合に

静的メンバ変数を利用すると便利です。(^^)

なぜなら、通常のメンバ変数と違い、オブジェクトごとにメモリ領域を

確保しないので、メモリを節約することができるからです。

たとえば、消費税率を入れるメンバ変数というのがある場合、この変数は

各オブジェクト共通で使用できるはずです。

もし、消費税率がそれぞれのオブジェクトのメンバ変数にあると、

それはメモリ領域の無駄遣いになります(-_-;)

また、静的メンバ関数というものもあります。

これは、静的メンバ変数のように共通のメモリ領域と使った関数ではなく、

静的なメンバ変数にしかアクセスできない関数のことです。(^^;)
使用例は次回以降で詳しくみていきます。

オブジェクトをメンバにする
今まで、変数や関数をメンバに持つクラスというものを紹介してきました。
さらに、オブジェクトそのものもメンバに加えることができます。(^^)

たとえば、時刻を計算したり、表現するTimeクラスのオブジェクトを作った場合

いろいろな所で、活用できそうです。

もし、予定表をつくるためScheduleクラスを作成するとしたら、

先のオブジェクトを利用すると簡単に作成できそうな気がします。

このように、配列、文字列や日付などあらかじめ用意しておくと

便利なオブジェクトはたくさんあります。

それらのオブジェクトを有効活用して、新しくクラスを作る手間を

削減できるようにしたいものです(^^;)


今日の名言
何かで悩みはじめ、頭の中が水車を動かしているエジプトのラクダのように
回転し始めると、私は体を十分に運動させて、こうした「憂鬱な気持ち」を
追い払うことにしている。悩みに対する最良の解毒剤は運動である。
悩みのある時は、できるだけ頭脳を使わずに筋肉を使うことだ。そうすれば、
その効果にびっくりするに違いない。私はいつもこの手を使う。
運動を始めると、悩みはすぐに消えてしまう。
                          エディー・イーガン大佐

もし世界中の人間の悩みを一つ所に積み上げてその人数に分け、平等に
分配したら、たいていの者は自分の取り分に満足して立ち去ることだろう。
                          ソロン

自分の悩みに「損害停止」の命令を出そう。これこれの事柄にはどのくらいの
不安が相当するか決定する-そしてそれ以上の不安は断るのである。
                          デール・カーネギー