2014年6月22日日曜日

デバッガの利用


ちょうどC#のサンプル

プログラムで

デバッガを使う部分が

あったので、ご紹介。




画像の左端の赤丸がブレイクをはっている部分です(4箇所)

今は2番目で停止しています。(黄色矢印部分が該当)

また、クイックウォッチという変数の値をチェックする機能もあります。

デバッグも簡単なので、IDEはやはり便利さを感じずにはいられません。

さて前回は、ソースプログラムを変更してデバッグする方法を紹介しました。

これは、自力でバグを見つけ出すための方法ですが、自分で学習するための

プログラムではいいかもしれませんが、実務でのプログラムになると

バグの発見やソースコードの変更が非常に大変になってきます。

そこで、ぜひ覚えておきたいのが、ツールの力を借りるということです。

デバッグを支援するツールのことを「デバッガ」といい、コンパイラと共に

プログラムの開発には欠かせないものです。

ここでは、代表的なデバッガの機能を紹介します。


ブレイクポイントの設定
デバッガを使えば、ソースプログラムの指定した位置でプログラムの動作を

停止させることができます。ブレイクポイントとは、その停止位置のことです。

ブレイクポイントを設定してプログラムを実行すると、その場所にきたときに

プログラムが停止します。

変数の表示と変更
ブレイクポイントでプログラムを一時停止した時に、そのときの変数の値を

参照することができます。要は、print文で出力するのと同じですが、

こちらの場合は、ソースプログラムを変更することなく、好きな変数の値を

表示させることができます。また、多くのデバッガでは変数の値を直接書き換え

その値でプログラムの実行を継続させることができます。

ただし、演算子をオーバーロードしているような場合は、見た目の記述どおりに

デバッガで表示できるとは限らないので注意が必要です。

ステップ実行
ソースプログラムの1行ごとに、プログラムを実行する機能です。

この機能は、プログラムが実際にどのように動作しており、どの時点で止まって

いるかを捉えることができるので、非常に役立ちます。

このとき変数の値を表示させておけば、値の移り変わりを調べることができます。

条件分岐が多いプログラムなどでは特に重宝するでしょう。


このようにデバッガを使うと、ソースプログラムを変更するよりはるかに

簡単で効率的にデバッグできるようになります。

デバッガが使える環境では、積極的にデバッガを利用して

時間と労力を節約したいものです。

もし、IDEの開発環境が整っていれば、たいていコンパイラとデバッガの

両方を備えているので、デバッグしやすいかもしれません。

しかし、Linuxでコマンドラインで開発してるような場合だと、デバッガが

用意されてなかったりとか、デバッグ版のバイナリを作成するのが

手間がかかりすぎるという場合もあって、ログを仕込んで実機検証の

方が早く解決できるということもあるでしょう。

既にある環境で開発する場合が圧倒的に多いので、

それに合わせてデバッグ手法も柔軟に変えるというのがおススメです(^^;)


今日の名言
人生をあるがままに受け入れない者は、悪魔に魂を売り渡す。
                               シャルル・ボードレール

幸福になる秘訣はできるだけ多方面に関心を持つこと。そして自分が関心を
持つ人物や事柄に対しては、なるべく腹立たしい気持ちを示さずに、できるだけ
親しい気持ちで接することだ。
                               バートランド・ラッセル

心は天国をつくり出すことも、地獄をつくり出すこともできる。
                               ジョン・ミルトン

人間は、起こることよりも、起こることに対する見解によってひどく傷ついてしまう。
                               ミシェル・エケム・ド・モンテーニュ

私たちが取り組むべき唯一最大の問題は、正しい考え方を選ぶことにある。
もしこれができたら、私たちの問題にはことごとく解決の道が開けていくであろう。
                               デール・カーネギー

2014年6月10日火曜日

デバッグ手法について



プログラムが意図したとおりに動かない時は、

バグ(誤り)を発見し修正する「デバッグ」という

作業を行わなければなりません。

ちなみに、サンプルプログラムは

全く意味のないものです(^^;)


エラーの種類
言語を問わず、プログラミングをしていてまず最初に突き当たる壁が

コンパイルエラーです。プログラムがコンパイルできない原因は、

文法が間違っている、コンパイル方法が正しくない、などがありますが、

どの部分が間違っているのかはたいていコンパイラが指摘してくれます。

ただし、コンパイラが出力するエラーメッセージは、良くも悪くも

「流れ作業的」なので、ほんの一箇所間違いがあるだけでも、それ以降で

整合性が取れず、エラーメッセージが多数出力されることがあります。

エラーメッセージがたくさん表示されたとしても、間違いと関係ないものも

ありますので、どのメッセージが本質的なものなのかを見極めることも

必要となります。

また、コンパイルでエラーになっていないからといって、それが正しく

動作するかは別の話です。

一番厄介なのは、プログラム実行中の不具合です。

例えば、プログラムが途中で止まる、あるいは異常終了するとか

動作は期待通りであるが、出力結果がおかしいなど、バグの種類も

様々です。

変数 a に5を代入は 「a = 5;」 と書きます。これを間違って「a == 5;」 と

イコールを二つ書いたとしても、a と 5 が等しいかどうかを比較する式

なので、文法的には正しく、コンパイルエラーにはなりません。

しかし、a に 5 は代入されず不定値のままなので、意図した動作に

ならないプログラムの出来上がりです(-_-;)


バグの発見
プログラムのバグを発見するには、まずソースコードをトレースするのが

基本です。そのロジックが正しいのかを再度確認する必要があります。

しかし、何度も見直したけどおかしいところはない、なぜ期待した結果と

異なるのか、と意外と誤りに気付かないケースもあります。

すぐに誰かに聞くのも一つの手ですが、まずは自分で解決するための

方法を押さえておきたいところです。


・ 処理を分割する
C++では、式や文の記述が非常に柔軟なので、かなり凝ったプログラムも

作ることができます。ただ、そういったものは他人には分かりにくく保守性

が悪い、いわゆる自己満足にしかならないプログラムとなる場合が多いです。

バグの温床にもなりますので、処理や意味の単位で分割することを

考えた方がよいでしょう。短く書こうとして、あまり一行にまとめすぎると

どこでエラーが起きているかも分かりにくくなります。

演算子の優先順位も間違いやすいところです。式の意味が分かりにくいとか

優先順位がはっきりしない、などの場合は、カッコをつけたり、一度変数に

代入すると読みやすくなるものです。

ポインタや配列の演算、インクリメント演算子などを多用すると

複雑になりますので、特に注意してください。

「困難は分割せよ」です(^^)


・ print文を挿入する
コンパイルしたプログラムを実行しただけでは、バグがあることは分かっても

原因の特定は難しいでしょう。このような時は、トレーサとして cout あるいは

printf を挿入して手がかりを掴めるようにします。例えば、プログラム中で

処理を分岐しているところに、cout << "実行1" << endl; 、cout << "実行2" << endl;

などと仕込んでおけば、そこに到達した時にメッセージが出力されますので

どの条件でこちらの処理が行われたのかがわかるというわけです。

また、そこで変数の値を表示するようにしておくのも非常に有効です。

ログは本当に重要なのです(^^)


・ 関数ごとに実行する
C++の処理の単位は関数です。関数に様々な引数を与えて、戻り値を調べれば

その関数が正常に動作しているかが分かります。関数は様々な状況で

呼び出されますが、デバッグしたい部分を切り出して main関数からすぐに

実行するようなテストプログラムを作成すれば効率的です。

ここでも「困難は分割せよ」ですね(^^)


・ throw文を記述する
ある条件の時に意図的に例外を発生させることで、エラー箇所とエラー内容を

特定できるかもしれません。 例外処理であるtry, catch文でエラー内容を

取得します。


・ assertマクロを記述する
assertマクロを使用すると、特定の条件が当てはまらない時に、メッセージを

出力してプログラムを強制終了することができます。値をあらかじめ評価して

おくことで、バグの早期発見につながります。 例えば、「assert(a == 5);」と

書いておくと、a の値が 5 でなくなった時に 「assertion failed」というメッセージを

出力して強制終了します。

assertマクロを使う時は、<assert.h> のインクルードが必要です。

上記の画像のプログラムを実行すると以下の結果になります。

# ./test
 start
as: as.cpp:18: int main(): Assertion `a == 5' failed.
中止


・ 処理の流れを限定する
バグが潜んでいる箇所を特定するには、条件分岐が邪魔になることが

あります。条件分岐は状況に応じて動作が変わるのでバグの位置が

分かりにくくなってしまいます。このような場合は、条件分岐の条件を

書き換えたり、どちらか片方だけを行うようにするのも一つの方法です。

この方法は、論理的にありえないエラーケースのテストなどにも有効です。


・ データ構造を推測する
時にはこれまで紹介したような方法だけでなく、推理力が

必要になることがあります。複雑なアルゴリズムやデータ構造の

プログラムでは、バグの箇所とは全く関係ない部分で異常な動作を

示すこともあります。そのような場合、いくらコードを見返しても

「ありえない」という結論にしか辿り着けません(-_-;)

ここはひとつ、メモリがどのように使われているのかを考えてみましょう。

また、データ構造を紙に書き出してみるというのもいいでしょう。

配列の範囲外にアクセスしたり、ポインタが間違ったところを参照して

いるため、突然異常終了するというのは非常によくあることです(^^;)

ありがちだけど、発見するのが難しい厄介な問題です...


さて、ここまでは自力で解決する方法を見てきました。

次回は、ツールに頼るというデバッガ利用についてです。


今日の名言
人間は幸福を求めてこそ意味ある存在である。そしてこの幸福は、人間自身の
中にある。つまり自分が生存するために、毎日必要なものを満足させるところに
あるのだ。
                                   レフト・トルストイ

多くの人々は、どこかほかの土地へ行きさえすれば、何か他の仕事につきさえ
すれば、それですぐ幸福になれると考えているが、ちょっと考えものだ。だから
自分の今手がけていることから、出来るだけ多くの幸福を得ることだ。そして
幸福になる努力を、またの日まで延ばさないことだ。
                                   デール・カーネギー

人間は、自分で努力して得た結果の分だけ幸福になる。ただしそのためには、
何が幸福な生活に必要であるか知ることだ。すなわち簡素な好み、ある程度の
勇気、ある程度までの自己否定、仕事に対する愛情、そして何よりも、清らかな
良心である。今や私は、幸福は漠然とした夢ではないと確信している。経験と
思考を正しく用いることにより、人間は自分自身から多くのものを引き出すことが
できる。決断と忍耐により、人間は自分の健康を取り戻すことすらできる。
だから人生をそのあるがままに生きよう。そして感謝を忘れないようにしよう。
                                   ジョルジュ・サンド

2014年5月31日土曜日

C++ 例外




コンパイル時のエラーなら、実行できないので

修正箇所も明確です。

しかし、コンパイルしたファイルを実行すると

エラーになることもあります。

この実行時エラーが、例外(Exception)です。

例外は、ゼロ除算やメモリの2重解放、配列の範囲外アクセスなどによって

起こります。実務では、どこで起こったのかすぐにわからないこともよくあります。

このような例外に対応することを例外処理といいます。(^^;)

C++には、例外処理のための仕組みが用意されています。

try, catch文
例外が起こりそうな箇所にtry、例外処理を行う箇所にcatch文を記述します。

構文はこのような形式になります。

try {
    // 例外が起こりそうな、ちょっと自信がないプログラム
}
catch (int &e) {
    // 例外処理
  // 例えば、エラーが起きたというメッセージの表示
}

実行時は、まずtry { } の中を処理し、例外が起こらなかった場合は、

catch { } の中は実行せずに処理を継続します。

もし、try { } の中で例外が起こった場合は、catch { } の中を

実行して、処理継続となります。

ここで、catchの部分に着目すると、catch (int &e) となっています。

カッコの中で、例外の型(クラス名)、変数名(オブジェクト)を指定して

どのような例外を捕捉するのかを決めることができるのです。

それはつまり、指定を間違うと例外が発生しても catch 文を実行せず

そのままスルーなんて事にもなる、ということです...(^^;)

ちなみにすべての例外を受け取るには

catch ( ... ) {
    // 何かの例外処理
}

このように、「...」 ピリオドを3つ記述します。


throw文
処理に応じて、意図的に例外を通知させたいこともあると思います。

その場合は、次のようにthrow文を使って例外の内容を通知できます。

try {
    int Number;
   
    cout << "Please Input Number : ";
    cin >> Number;
    if (Number < 0) { throw -1; }
    cout << "Input Number : " << Number << endl;
}
catch (int error) {
    cout << "負の数はエラーです。エラーコード: " << error << endl;
}


では、今回はメモリをひたすら確保し続けるサンプルコードを使い

try, catch してみるという実験を以下に示します。

100MBメモリ確保して、文字 'a' で初期化を繰り返すプログラム
#include <iostream>
#include <new>        // bad_allocのcatchに必要です
#include <string.h>

using namespace std;

int main(void)
{
    try {
        // 100MB確保を繰り返す
        for (int i = 1; ; i++) {
            char *pStr = new char[104857600];
            cout << i * 100 << "MB" << endl;
            memset(pStr, 'a', 104857600);
        }
    }
    catch (bad_alloc &) {
        cout << "'new' threw an exception..." << endl;
        return -1;
    }

    return 0;
}

実行結果
# ./test
100MB
200MB
'new' threw an exception...
#

ただメモリを確保しただけだと、OSには実際は使っていない

ということが分かっているので仮想メモリを駆使して実メモリ以上を

確保しているように見えます。手元の環境では、3000MBまで到達(^^;)

そのため、memsetで初期化することで、使用していることをアピールします。

非力なマシンなので、すぐに力尽きてしまいました...


結局、何が言いたいのかというと、例外処理はバグの早期発見に役立つ、

品質の良いプログラムを作るための一機能であるということです。(^^)


今日の名言
時の与えるあらゆる利益を迅速に利用せよ。
                               ウィリアム・シェイクスピア

過去の過ちから役に立つ教訓を引き出すためと、高価な代償を払って得た利益を
得るためでない限り、決して過去を顧みるな。
                               ジョージ・ワシントン

憎しみは、他のどんなものよりもエネルギーを消耗する。その消耗のひどさは、
重労働よりも病気よりも、ちゃんと理由があって心配する場合よりも、はるかに
はなはだしい。だから憎しみの炎が自分の体の中へ入ってきたら、すぐさま
消すことだ。その代わりに美しい考えを入れてやろう。我々の精力は神から
授かった貴重なものだから、価値のある者だけに費やさねばならぬ。
                               デール・カーネギー

2014年5月17日土曜日

C++ ヘッダファイルの記述方法




今日は、ヘッダファイルの書き方について

の話になります。

今までは、短いサンプルということもあり、

一つのソースファイル(.cpp)の中に

クラスの定義を記述していました。

しかし、普通はクラスの定義はヘッダファイル(.h)に

記述し、メンバ関数の定義をソースファイル(.cpp)に記述します。

つまり、画像の例でいうと、Peach.h にこれを書いて、

class PeachBox {
public:
    PeachBox();
    ~PeachBox();
    int GetTotal();
private:
    int m_total;
};

Peach.cpp にはこれを書きます。

PeachBox::PeachBox():
m_total(0)
{
}

PeachBox::~PeachBox()
{
    std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}

int PeachBox::GetTotal()
{
    return m_total;
}

int main(void)
{
    PeachBox myPeachBox;
    std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
    return 0;
}


さて、このようにヘッダファイルとソースファイルを分割したことによって、

例えばFood.hといった他のヘッダファイルでPeach.hをインクルードする、

あるいは Peach.cpp から Food.h をインクルードするといった、

少し規模が大きいプログラムでも便利に使えるようになります。

しかし、色々なファイルで #include を使っていると、結果的には同じヘッダファイルを

2度インクルードしてしまうこともあります。

この場合は、クラスを2度定義することになり、コンパイルエラーになります(-_-;)

試しにPeach.h では Food.h をインクルードしてみます。

#include "Food.h"

class PeachBox {
public:
    PeachBox();
    ~PeachBox();
    int GetTotal();

そして、Peach.cppを、こんな感じに変更します。

#include <iostream>
#include "Food.h"
#include "Peach.h"

PeachBox::PeachBox():
m_total(0)
{
}

実際やってみると、Food.hを2回インクルードしているので、もちろんエラーです(^^;)

ちなみに、Peach.h Peach.cpp は同じディレクトリにあるので

これでコンパイルできています。

# g++ -g -Wall -o Peach Peach.cpp
In file included from Peach.h:1:0,
                 from Peach.cpp:3:
Food.h:4:7: error: redefinition of ‘class Food’
Food.h:4:7: error: previous definition of ‘class Food’

こういう時のために、重複インクルードを防ぐための

#ifndef マクロ というプリプロセッサ命令があります(^^)

プリプロセッサとは、コンパイラに対してコンパイルする前に、

事前処理を行わせるためのプログラムのことです。

言葉だけでは、伝わらないので実際に使ってみます。

Food.h
ifndef __FOOD_H  // もし、__FOOD_Hが未定義なら
#define __FOOD_H  // 最初のインクルードで__FOOD_Hを定義します
             // こうすることで、2回目以降は既に__FOOD_Hが
            // 定義されているので、この内容は
            // インクルードされなくなります(*^^)v
#include <iostream>
#include <string.h>

class Food
{
public:
    static double sm_tax;
    void SetPrice(int price);
    int GetPrice(void);
private:
    int m_price;
};

#endif // __FOOD_H  ←通常、目印としてコメントを記述しておきます

Peach.h
#ifndef __PEACH_H
#define __PEACH_H

#include "Food.h"

class PeachBox {
public:
    PeachBox();
    ~PeachBox();
    int GetTotal();
private:
    int m_total;
};

#endif // __PEACH_H

Peach.cpp
#include <iostream>
#include "Food.h"
#include "Peach.h"

PeachBox::PeachBox():
m_total(12)
{
}

PeachBox::~PeachBox()
{
    std::cout << "桃の化粧箱オブジェクトが終了します。" << std::endl;
}

int PeachBox::GetTotal()
{
    return m_total;
}

int main(void)
{
    PeachBox myPeachBox;
    std::cout << "化粧箱の中の桃の数は" << myPeachBox.GetTotal() << "個です。" << std::endl;
    return 0;
}

コンパイルと実行結果
# g++ -g -Wall -o Peach Peach.cpp
# ./Peach
化粧箱の中の桃の数は12個です。
桃の化粧箱オブジェクトが終了します。

2重インクルードしているにもかかわらず、エラーにならず実行できました。

ただ Food.cpp を作成してメンバ関数を定義していないし、

Peach.cpp 内で使ってもいないので、

Food.h をインクルードする必要のない、

例によって全くおもしろみもないプログラムです...(^^;)

ここでは、重複インクルード防止のための方法として、

#ifndef, #define, #endif という構文を見てきました。

プリプロセッサを使いこなして、品質の良いプログラムを造っていきたいものです。


今日の名言
子供には過去も未来もない、だから現在を楽しむ - 大人はとてもそうはいかない。
                               ジャン・ド・ラ・ブリュイエール

明日をはじめる前に今日をすっかり終える。今日と明日との間に眠りの壁を置く。
これをやり遂げるには、節制の心がけが必要だ。
                               ラルフ・ワルド・エマーソン

ある者は過去の記憶を蒸し返して、我と我が身を苛み続ける。
ある者はまだ見ぬ罪におびえて、我と我が身を傷つける。
どちらも愚かきわまることだ。 - 過去はもはや関係がなく、未来はまだ来ぬ・・・。
                               セネカ

時の真の価値を知れ。引っ掴め。押さえつけろ。そしてその瞬間瞬間を楽しめ。
怠けず、だらけず、ぐずぐずするな。今日できることを明日まで伸ばすな。
                               チェスターフィールド卿

2014年4月26日土曜日

C++ キャスト演算子



もはやメモリが少なくとも8Gは

必要な時代が来ているのかもしれません。

起動しただけで2G以上使っており、

何か作業をしようとプログラムを起動するにも

あまりにモッサリした動きになるので



システムのパフォーマンスオプションをパフォーマンスを優先するにしてみました。

ただ4G程度では、まだ足りないというのか...

こういうのは、思い至った時は大抵高いのが嫌なところ。



今時期は安くてもこの程度か...

6K位まで落ちれば、買ってもいいと思うかもしれない。



さて、今回はキャストの話です。(^_^;)

C では、値や変数を特定の型に変換したい時は、次のようにしていました。

// とあるスレッド関数
void *something_thread_func( void *arg ) {
    // 引数をとある構造体にキャスト
    something_struct_t *pSomeStruct = (something_struct_t *)arg;
        :
        :

C++ では、このようなキャストを行ってもエラーにはなりませんが、

できるだけ C++ で追加したキャスト演算子を使うようにしたいものです。(^_^)

これらのキャスト演算子は、ポインタ型や参照型を、別の型に変換します。

※ここでは、 V という型を T型に変換することを意味しています。


const_cast<T>(V)          const を取り除くのに使います。

dynamic_cast<T>(V)      基底クラスのポインタ(あるいは参照)を派生クラスの
                                 ポインタ(あるいは参照)に変換するのに使います。

static_cast<T>(V)          C のキャストに近い使い方ができます。
                  const は取り除くことはできません。

reinterpret_cast<T>(V)  関数ポインタを別の関数のポインタへ変換したり
               ポインタをint型などへ変換するときに使います。
               全く違う型へキャストした場合は不正アクセスを
               引き起こしやすいため、注意が必要です。
               どうしても必要なときだけ使うようにした方が良いでしょう。


そして、先程の例をキャストすると、こうなります。(^_^;)

// とあるスレッド関数2回目
void *something_thread_func( void *arg ) {
    // 引数をとある構造体にキャストした2回目
    something_struct_t *pSomeStruct = static_cast<something_struct_t>(arg);
        :
        :

このように、C++ のキャスト演算子を使うと、間違ったキャストをした場合に

コンパイルエラーになります(´・ω・`)

そのため、C の書き方よりも安全なキャストとなります。

また、_cast が付いているので、キャストした場所がわかりやすくなります。

grep で探すときも便利ですね(^_^)


今日の名言
もし「時」がこの世で最も貴重なものだとすれば、時の浪費ほど大きな浪費は
あるまい。失われた時は二度と帰らないからだ。時はいくらあっても十分では
ないのが常だから、やるべきことはさっさと行おう。価値あることを行おう。
精を出してことに当たれば、これまでよりてきぱきとやれるはずだ。
                              ベンジャミン・フランクリン

私は明日を恐れない。なぜなら私は、昨日を知ったし今日を愛しているからだ。
                              ウィリアム・アレン・ホワイト

君の毎分毎分を大切にすることをおすすめする。時間のほうは時間が自分で
世話をするだろうから。
                              チェスターフィールド卿

一度に一歩ずつ登れば、高い山でも踏破できる。
                              ジョン・ワナメーカー

2014年4月10日木曜日

C++ 代入演算子のオーバーロード





前回の演算子のオーバーロードに続いて、

今度は代入演算子をオーバーロードします。







operator= ()関数は、オブジェクト同士の代入が行われたときに呼び出されますが、

演算子のオーバーロードと同様に、operator= ()関数をオーバーロードして

クラスを代入する新しい = (代入演算子)を定義してみます。

では、さっそくサンプルプログラムです。

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

using namespace std;

class Person {
public:
    Person() {
        m_StrName = NULL;
    }
    Person(char *StrName) {
        // 勝手に128文字までに制限
        int nLen = strnlen(StrName, 128);
        m_StrName = new char[nLen + 1];
        strncpy(m_StrName, StrName, nLen + 1);
    }
    ~Person() {
        if (m_StrName != NULL) {
            delete [] m_StrName;
            m_StrName = NULL;
        }
    }
    Person & operator=(const Person & Psn);
    char *GetPersonName() {
        return m_StrName;
    }
private:
    char *m_StrName;
};

// 代入演算子のオーバーロード
Person & Person::operator=(const Person &Psn)
{
    // 自分自身の代入では、何もしない
    if (this == &Psn) return *this;

    // それまでのメモリを解放
    if (m_StrName != NULL) {
        delete [] m_StrName;
        m_StrName = NULL;
    }

    // 新しくメモリを確保して、文字列をコピーする
    // やはりここでも128文字制限
    int nLen = strnlen(Psn.m_StrName, 128);
    m_StrName = new char[nLen + 1];
    strncpy(m_StrName, Psn.m_StrName, nLen + 1);

    return *this;
}

int main(void)
{
    Person Psn1((char *)"ABCDEFG");
    Person Psn2((char *)"TUVWXYZ");

    cout << Psn1.GetPersonName() << endl;
    cout << Psn2.GetPersonName() << endl;

    // 代入する 
    Psn1 = Psn2;

    cout << "---" << endl;

    cout << Psn1.GetPersonName() << endl;
    cout << Psn2.GetPersonName() << endl;

    return 0;
}

実行結果
# ./test
ABCDEFG
TUVWXYZ
---
TUVWXYZ
TUVWXYZ


ABCDEFGという名前が代入によってTUVWXYZに変わったという
例によって、あまりおもしろくないプログラムです。(^_^;)

ただ、デフォルトのoperator= ()ではメモリ確保などは行われないため
一応独自の動作が定義できています。

代入のところでは、Psn1オブジェクトのoperator= () が呼ばれ、
Psn2オブジェクトが引数に入るという動きになっています。

そしてoperator= ()が自分自身を返すのは、Psn1 = Psn2 という式が
さらに代入される場合があることを考慮しているからです。


ところで、Person Psn3 = Psn2; のようなオブジェクト生成時の
初期化の場合は、コピーコンストラクタが呼ばれます。
似ているので注意しておきたいところです。(^_^;)


今日の名言
常に現在の時間にしっかりしがみつけ。刻一刻すぎていく時間には、無限の価値がある。
私は現在に自己の全てを賭けている。一枚のトランプに人が大金をかけるように。
私は現在をそっくりそのままで、できるだけ高価なものにしようと努力しているのだ。
                            ヨハン・ウォルフガング・フォン・ゲーテ

今ここで征服できない時間は、永久に征服できない。今ここで楽しめない人生は、
永久に楽しめない。今ここで賢明な生活を送らなければ、永久に賢明な生活は
できない。過去はもはや存在せず、未来は誰にも分からないのだから。
                            デイヴィッド・グレイソン

もし、悩みに関して古今の大哲学者が書いた言葉の全てを要約すれば、次の
二句に尽きる。
「橋のたもとに行き着くまでは橋を渡るな」、「覆水盆に返らず」
                            デール・カーネギー

ありていに言えば、現在に生きる者はごく少ない。誰も彼も、現在以外の時に
生きるつもりなのだ。
                            ジョナサン・スウィフト

2014年4月1日火曜日

C++ 演算子のオーバーロード




演算子をオーバーロードすると、クラスごとに

演算子の機能を定義できるようになります(^^)


因みにオーバーロードは、日本語で書くと

多重定義です。



一方、言葉が似ているため、とても間違いやすく混同しがちなオーバーライドは

機能の上書き、あるいは再定義となります。(^^;)

何度も繰り返し唱えて、覚えてしまいたいものです...(^^ゞ

さて、演算子のオーバーロードですがC++では、 + や - といった既にある

演算子に対して、独自の機能を定義することができます。

使いどころとしては、単純に四則演算しただけでは期待する結果に

ならないだとか、2つ以上のあるデータの組に対して演算を行いたい場合

などが当てはまるでしょう(^^)

ここでは、+演算子をオーバーロードして、オブジェクト同士の加算を

行ってみたいと思います。 

時刻の加算結果を求めるサンプルです。

#include <iostream>

using namespace std;

class ClockTime {
public:
    ClockTime() {};
    ClockTime(int nHour, int nMinute) {
        m_nHour = nHour;
        m_nMinute = nMinute;
    }
    ClockTime operator+ (const ClockTime &Ct2);

    int m_nHour;
    int m_nMinute;
};

// +演算子のオーバーロード
ClockTime ClockTime::operator+ (const ClockTime &Ct)
{
    int nHourBuf = 0;
    int nMinuteBuf = 0;
    int nTotal = 0;

    nTotal = (m_nHour * 60 + m_nMinute) + (Ct.m_nHour * 60 + Ct.m_nMinute);
    nHourBuf = nTotal / 60;
    nMinuteBuf = nTotal % 60;

    // 自分自身と同じクラスのオブジェクトを戻す
    return ClockTime(nHourBuf, nMinuteBuf);
}

int main(void)
{
    ClockTime Ct1(1, 23);  // 1時間23分
    ClockTime Ct2(4, 56);  // 4時間56分
    ClockTime Ct3;

    // オブジェクト同士を加算
    Ct3 = Ct1 + Ct2;

    // この例で期待通りとなる値は 6時間19分
    cout << Ct3.m_nHour << "時間 " << Ct3.m_nMinute << "分" << endl;

    return 0;
}

実行結果
# ./test
6時間 19分

いつものようにたいしておもしろくないプログラムですが、

期待通りの結果となりました。(^_^;)

ClockTimeクラスの中で、 operator+() 関数を定義しているため

Ct3 = Ct1 + Ct2; の式での + は、Ct1オブジェクトの operator+()が

呼ばれるようになります。

また、ClockTime ClockTime::operator+ (const ClockTime &Ct) の

引数として渡されるているのが、Ct2オブジェクトとなっています。

結果、時刻を加算するという +演算子のオーバーロードができました(^_^;)

ちなみに、 -演算子では operator-()関数をオーバーロードします。

*, / といった他も同様です。

オブジェクト指向の素晴らしさを垣間見ることができますね。

今日の名言
現在の一瞬はこのうえなく素晴らしい一瞬である。今、夕食に5分遅れることは、
十年間の大きな悲しみより重要である。
                              サミュエル・バトラー

いくら苦しくても現実をしっかり見つめることだ。目標をしっかり定める。
いったん目標が定まったら、ありとあらゆる時間をその実現のために
注ぎ込む。自分の決心が正しいかどうか心配して、貴重な時間を浪費
するな。あくまでやり通せ!
                              デール・カーネギー

過ぎ去りし麗しき一日は、再び我がもとに帰り来たらず。
                              アルフレッド・テニソン卿

我々はここにいる。そしてそれは今だ。それより先のことについての人間の
知識は、すべて月光のごとくとりとめがない。
                              ヘンリー・L・メンケン

2014年3月21日金曜日

C++ 標準テンプレートライブラリ 其の弐(2/2)





第二弾は、イテレータ(反復子)の話です。


イテレータとは、コンテナオブジェクトにある


 iterator クラスのオブジェクトで



これを使うと、コンテナオブジェクトの中のデータに同じように

アクセスできるようになります(^^;)

つまり、配列でもリストでも同じアクセス方法になる、ということです。

iterator オブジェクトは、各コンテナオブジェクト用のものがあり、

その中の1つの要素を指します。

では、いつものようにサンプルプログラムです。

#include <iostream>
#include <vector>

using namespace std;

int main(void)
{
    vector<int> nVec;

    nVec.push_back(5);
    nVec.push_back(10);
    nVec.push_back(15);
    nVec.push_back(20);

    // vectorクラスでイテレータを使う場合の宣言方法に注目
    vector<int>::iterator itr_first, itr_last, i;

    itr_first = nVec.begin();  // 最初の要素をイテレータに代入
    itr_last = nVec.end();     // 最後の要素をイテレータに代入

    cout << "要素数は " << (int)nVec.size() << " です。" << endl;

    cout << "すべて出力してみます。" << endl;
    // 要素を取り出すのにイテレータでカウンタを操作
    for (i = itr_first; i != itr_last; i++) {
        cout << *i << endl;    // イテレータから値を参照しています。
    }                               // ポインタのようですね(^^;)

    return 0;
}

実行結果
# ./test
要素数は 4 です。
すべて出力してみます。
5
10
15
20


このように、ちょっと使うだけでもSTLの素晴らしさが分かります(^^)

開発を効率化する便利なものはどんどん使ってものです...


今日の名言
一年前にあなたが悩んでいた事柄を思い出していただきたい。どうやってそれを
切り抜けただろうか。そうした悩み事ばかり気にかけて、エネルギーを
浪費しなかっただろうか。結局そうした悩みは、ほとんどが取り越し苦労だった
のではないか?
                               デール・カーネギー

今日行いたい善行があれば、すぐに実行せよ。決して明日まで延ばすな。
                               ジェフリー・チョーサー

現在我々が経験している時間と状況は、それまでの時間と状況が積もり積もって
出来た結果である。これは大自然がこれまでに振り出した、あるいは
振り出すことのできる、最上の賽の目である。
                               ラルフ・ワルド・エマーソン

何より大事なことだが、我々は現在にしか生きられないのだ。過去を顧み、
人生の一瞬たりとも無為に過ごしたことはなかったと言いきれる者は、
最も幸福な人間である。
                               ヘンリー・デイヴィッド・ソロー

2014年3月14日金曜日

C++ 標準テンプレートライブラリ 其の壱(1/2)






今回はC++の標準テンプレートライブラリ

Standard Template Library についての話です。






標準テンプレートライブラリとは、配列、リスト、キューのような複数のデータを

管理したい場合に、その実装に頭を悩ませることなしに利用できる

大変便利なクラスやアルゴリズムの集合です。(^^)

また、複数のデータを格納して管理するオブジェクトのことを

コンテナオブジェクトといいます。

一例として次のようなものがあります。

  • 配列      vector
  • リスト     list
  • キュー    queue
  • スタック  stack
  • 集合      set

まだ、他にも色々ありますが、ここで全て扱うには難しい内容ですし

割愛させていただきます...(^^;)

あれこれ難しいことを考える必要がないし、汎用的で高機能という

素晴らしさを兼ね備えているのですが、メモリ制約がある組み込み

ソフトウェア開発においては、当然使えません...(-_-;)残念

そんなわけですが、例によって簡単なプログラムを用意しました。

今回は、vectorクラスを使ってみます。(^^)

これのスゴいところは、メモリが足りない時に自動的にメモリを

確保することです。

#include <iostream>    // vectorクラスを使います
#include <vector>

using namespace std;

int main(void)
{
    vector<int> nVec;    // int型のvectorオブジェクトを生成

    nVec.push_back(5);    // データを格納しています...
    nVec.push_back(10);
    nVec.push_back(15);

    // これで要素のサイズが分かります
    cout << "要素数は " << (int)nVec.size() << " です。" << endl;
 
    // 中身を確認してみましょう
    for (int i = 0; i < (int)nVec.size(); i++) {
       // 通常の配列と同じようにアクセスできます:-)
        cout << "vectoro[" << i << "] = " << nVec[i] << endl;
    }

    return 0;
}

実行結果
# ./test
要素数は 3 です。
vectoro[0] = 5
vectoro[1] = 10
vectoro[2] = 15


最初に配列の要素を決めなくてよいとは、何と便利...

しかも、動的にメモリ確保してることを全く意識させませんね。

いやぁ、STLを使えるってホントに素晴らしいですね(^-^)


今日の名言
結局のところ、最悪の不幸は決して起こらない。たいていの場合、
不幸を予期するから悲惨な目に合うのだ。
                           オノレ・ド・バルザック

一日を顧みて、どこかおもしろかった、楽しかった、本当に満足だったという
ところがなければ、その一日は無駄に過ごしたことになる。私にとって、
それは神に背くことであり、よこしまなことなのだ。
                           ドワイト・D・アイゼンハワー

最悪の事柄を受け入れてしまえば、もはや失うものはなくなる。
裏を返して言えば、どう転んでも儲けものなのだ!
                           デール・カーネギー

時間を浪費するな、人生は時間の積み重ねなのだから。
                           ベンジャミン・フランクリン

2014年3月5日水曜日

C++ テンプレートクラス





テンプレートクラスとは、使用する型を
曖昧な状態で定義しておくクラスです。


テンプレートクラスの機能を使うことで、
複数の型に対応することができます。(^^)




// 三辺の長さから、三角形の面積を求めるクラス
template<class T>  // T はテンプレート引数です(^^;)
class Triangle {
public:
    Triangle(T a, T b, T c) {
        m_a = a;
        m_base = b;  // 辺b を底辺としよう(^^;)
        m_c = c;
    }
    T GetHeight() {
        return ((m_a + m_base + m_c) / 2) * 2 / m_base;
    }
    T GetSummation() {
        return (m_a + m_base + m_c) / 2;  // ヘロンの公式
    }

    T m_a, m_base, m_c;
};

テンプレートクラスのオブジェクトを生成する場合は、次のように
使用する型を指定します。

Triangle<int> IntTriangle;             // int型を指定します
Triangle<double> DoubleTriangle;  // double型を指定します

また、テンプレート引数が二つ以上ある場合は、次のように
複数指定します。

template<class T1, class T2> // テンプレートなだけにT1, T2
class Triangle {
    :
};
    :
Triangle<int, double> tri;  // int型、double型を指定します
    :

それでは、今回のサンプルプログラムです。
#include <iostream>

using namespace std;

template<class T>  // T はテンプレート引数です(^^;)
class Triangle {
public:
    Triangle(T a, T b, T c) {
        m_a = a;
        m_base = b;
        m_c = c;
    }
    T GetHeight() {
        return ((m_a + m_base + m_c) / 2) * 2 / m_base;
    }
    T GetSummation() {
        return (m_a + m_base + m_c) / 2;
    }

    T m_a, m_base, m_c;
};

int main(void)
{
    Triangle<int> tri1(59, 50, 100);
    cout << "a = 59, b = 50, c = 100" << endl;
    cout << "height = " << tri1.GetHeight() << endl;
    cout << "   sum = " << tri1.GetSummation() << endl;

    cout << "---" << endl;

    Triangle<double> tri2(12.3, 45.6, 78.9);
    cout << "a = 12.3, b = 45.6, c = 78.9" << endl;
    cout << "height = " << tri2.GetHeight() << endl;
    cout << "   sum = " << tri2.GetSummation() << endl;

    return 0;
}

実行結果
# ./test
a = 59, b = 50, c = 100
height = 4
   sum = 104
---
a = 12.3, b = 45.6, c = 78.9
height = 3
   sum = 68.4

うーん、書いておいてなんですが合っているのかどうかが
分からないですね...(-_-;)

ちなみに、面積を求めるときのヘロンの公式をググったときに
面積 S とあったのですが、ふとこの S が何の略か気になり
これもまたググったところ、数学界の定説は

和を表すsumあるいはsummationの頭文字

とのことです。

surface じゃなかったんだ...|д゚)


今日の名言
今日気にかかることで、明日も気にかかることはめったにない。だから夜、
床につく時、たいていの悩みに対しては、安心してこう言い聞かせられる。
「お前には全力を尽くした。今後もう会うことはあるまい」
                          ウィリアム・クーパー

私は未来のことを考えない。あっという間にやってくるからだ。
                          アルバート・アインシュタイン

神の到来を待ち望む者は、自分が神の御手の中に現在いることが
分からない。神と幸福は不離一体であるという信念を抱いて、あらゆる
幸福を現在のこの一瞬の中に注ぎ込むことだ。
                          アンドレ・ジード

落し物の広告。昨日、日の出から日の入りの間のどこかで、それぞれ
六十分のダイヤモンドをちりばめた貴重な時間を二つ紛失。
なお拾い主には賞金なし。永遠に失われしゆえ。
                          ホレス・マン

2014年2月25日火曜日

C++ テンプレート関数




テンプレート関数の機能は

複数の型に対応した関数を

つくれることです(^^)






テンプレート関数とは、引数や戻り値の型が曖昧な状態の関数です。

そのためコンパイラが、テンプレート関数の呼び出し方を判断して、

具体的な関数に置き換えて処理するのです(*^^)v 賢い!

template<class T>
T GetMaxValue(T num1, T num2)
{
    T temp;

    if (num1 > num2) temp = num1;
    else temp = num2;

    return temp;
}

この class T とか書いてあるところが、テンプレート引数というものです。

別に T である必要はありませんが、分かりやすいし無難に倣っておくのが

良いのではないかと... テンプレートのTということで。(^^;)

仮の型名なので、関数を使用するときに int や double に置き換わります。

ここでは、関数の引数と戻り値に使っています。

関数の呼び出し方法は、特に変わった点はなく

普通に呼び出すだけで使えます(^^)

では、サンプルプログラムで見てみましょう。

include <stdio.h>
#include <iostream>

using namespace std;

// 与えられた引数のうち大きいほうの値を返します
template<class T>
T GetMaxValue(T num1, T num2)
{
    T temp;

    if (num1 > num2) temp = num1;
    else temp = num2;

    return temp;
}

int main(void)
{
    int a = 10;
    int b = 15;
    double c = 3.14;
    double d = 1.23;

    printf("a : %d, b : %d\n", a, b);
    int ans = GetMaxValue(a, b);  //int型を指定した呼び出し
    printf("ans : %d\n", ans);

    cout << "c : " << c << ", d : " << d << endl;
    double ans2 = GetMaxValue(c, d); //double型を指定した呼び出し
    cout << "ans2 : " << ans2 << endl;

    return 0;
}

実行結果
# ./test
a : 10, b : 15
ans : 15
c : 3.14, d : 1.23
ans2 : 3.14

Cでは、int型用、double型用などと2つの関数を

用意しなければなりませんでしたが、

このように一つにまとめることができました。

さすが、C++ 

インクリメントされてるので、ちゃんと進んでるのがわかりますね(^^;)


今日の名言
取り越し苦労をして先のことばかりに目を向け、まだ嵐がやってこない
うちから気をもんで、どうやって防ごうかとうろたえるようでは、神に対する
信頼を失ってしまう。まだこれからどうなるかわからないのに、打つ手や
失敗した時のことまで考えて、わが身を地獄に陥れるとき、我々は
恐怖心を追放してくれるあの「完全な愛」(神)から、完全に見放されて
いるのだ。
                         ヘンリー・ウォード・ビーチャー

まず確かな事実を手元に集めることだ。公平な目でありとあらゆる
事実を集めないうちには、問題に手も触れないことにしよう。
                         デール・カーネギー

ついに起こらなかった害悪のために、我々はいかに多くの時間を
費やしたことか!
                         トーマス・ジェファーソン

2014年2月11日火曜日

C++ 上級編の話



長い間続いた基礎編のネタが終了し、

ついに上級編の部類に突入しました。

では、さっそく見ていきましょう(^^)




テンプレート関数

テンプレートとは、ワープロやデザインなどで使われるフォーマットやデータのことです。

日本語で言うところのひな型、型紙というやつですね。

C++では、テンプレート関数という便利な機能があります。

これは呼び出し側で指定した引数の型に合わせて、関数内で使用する変数の値を

変えることができるというものです。

凄いところは、同じことを C でやろうとすると、引数の型が違うだけの別の関数を

用意する必要がありました。 安直にHogeFunc2() のように...(-_-;)

あとはちょっと気の利いた対応方法として、#define マクロを使う方法があります。

しかし、 #define だと一行で記述しなければならないので、複数行に亘る場合

\ 記号を使って行を連結する必要があります。

これだと分かりにくいし、何より \ 記号を付けるのが面倒でしょうがないデス(>_<)

#define SwapNum(T, a, b) \
        { T tmp = a; \
          a = b;       \
          b = tmp; }

int main(void)
{
    int a = 10;
    int b = 15;

    printf("a : %d, b : %d\n", a, b);
    SwapNum(int, a, b);
    printf("a : %d, b : %d\n", a, b);

    return 0;
}

C++では、テンプレート関数の機能を使えば、複数の型に対応した

関数を記述できるようになります。

#define マクロを使わない方法もあるということを押さえておきたいところです。


演算子のオーバーロード

C++にも足し算のときの + 、掛け算やポインタで使う * 、代入のときの = など

たくさんの演算子があります。

int 型やchar 型という普通の変数の型に対し、何かこれらの演算を行った場合

行われる処理は既に決まっています。

例えば int 型の2つの変数 a, b に対して + 演算子を使うと、2つの値を

足し算する筈...、ですよね(^^)

しかし、オブジェクトに対して同じことをしようと思った場合、

そのまま使うことはできません(^_^;)

もし使いたい場合は演算子をオーバーロードする必要があります。

演算子をオーバーロードすると、既にある演算子に独自の働きを

持たせることができるようになります。 

便利な使い方の例としては、+演算子のオーバーロードで

時間を表現する2つのオブジェクトを足すと

繰り上げ計算を行った上で、合計時間を求める、とか

= 演算子をオーバーロードして、

オブジェクト同士の代入が行われると、

動的に確保したメモリも含めまるっとコピーする

などがあります(^_^;)

少々難しい内容ですが、こちらもぜひ押さえておきたいところです。

今日の名言
みじめな気持になる秘訣は、自分が幸福であるか否かについて
考えるひまを持つことだ。
                         ジョージ・バーナード・ショー

じぶんがいまかかっている病気を我慢する方が、決してかからない
かもしれない病気について思い悩むより利口である。
                         ラ・ロシュフコー

現在の重荷に耐えきれない人間はいない。現在の重荷に過去の
重荷が加わるから、耐えられなくなるのだ。
                         ジョージ・マクドナルド

有名な法律についての金言を掲げよう。「法律は小事に関与せず」
悩みから逃れて、心の安らぎを求めるならば、小事にこだわっては
ならない。
                         デール・カーネギー

困難を予期するな。決して起こらないかもしれぬことに心を
悩ますな。常に心に太陽を持て。
                         ベンジャミン・フランクリン

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クラスを作成するとしたら、

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

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

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

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

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


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

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

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