2013年11月29日金曜日

C++ 継承


継承とは、すでにあるクラスを利用して、新しいクラスを作ることです^^
基にするクラスを基底クラス、基底クラスを継承して作ったクラスのことを
派生クラスといいます。

例えば、親クラスとして Food クラスを定義します。
そして、このFoodクラスのメンバに、新たにメンバを追加したVegetableクラス
というものを作りたいとします。
ここで、継承の機能を使えば、Foodクラスのメンバを受け継いだ子クラスが作れるのです。
受け継いだということは、もちろん親クラスのメンバ自身も使用できます。(^^)

少々分かり難いと思いますので、ソースコードで表現してみるとこんな感じになります。

基底クラス(Food)
class Food {
public:
    void SetPrice(int price);
    int GetPrice( );
private:
    int m_price;
};

基底クラスを継承したクラス(Vegetable)
class Vegetable : public Food {
public:
    void SetFarmName(const char *farm);
    void GetFarmName(char *farm);
private:
    char m_strFarmName[32];
};

あるクラスを継承した派生クラスを作るには、派生クラスのクラス名の後に
「: public 基底クラス名」を記述します。
publicのところは、privateやprotectedも記述できますが、ほとんど見かけません(^^;)
おそらく、あまり使うべき場面がないからでしょう。難しくなりますし...

派生クラスのメンバは自分のクラスのメンバ + 基底クラスのとなります。
したがって、派生クラスには書いてないのですが、Vegetableクラスでは
SetPrice()とGetPrice()のメンバ関数を使うことができます(*^^)v
やりますな、継承...

また、派生クラスは、基底クラスからいくつでも作ることができます。
そして、派生クラスを継承して、さらに派生クラスを作るという使い方もできます。

Food クラス - Vegetable クラス - Pumpkin クラス
                 |
                 |_ Fruit クラス      -  Peach クラス
                 |            |_  Orange クラス
                 |                        |_  Banana クラス
                 |_ Meat クラス

//オレンジ、バナナ、とくれば、次はブドウ ロックシード... (*´Д`)




今日の名言
どんな不幸な人生からでも、利口者は何らかの利益を得る。一方、どんな幸福な
人生からでも愚か者は心を傷つけられる。
                                        ラ・ロシュフコー

繁栄は偉大な教師であるが、苦難はさらに偉大な教師である。富は心を豊かにする。
貧苦は心を鍛える。
                                        ウィリアム・ハズリット

敗北は骨を硬く鍛える。敗北は軟骨を筋肉に変える。敗北は人間を不敗にする。
                                   ヘンリー・ウォード・ビーチャー

敗北とは何か。それは教育にほかならない。それは一段と優れた段階に達するための
第一歩なのだ。
                                     ウェンデル・フィリップス

光の存在が物を見えるようにし、また見えなくもしている。けれどたとえこのうえなく気高い
創造物でさえ、暗黒と地上の影がなければ、いつまでも人の目にとまらない。
そして天空の星も見えなくなる。
                                     サー・トーマス・ブラウン

2013年11月27日水曜日

C++ 継承概要

「継承」は、オブジェクト指向プログラミングの特徴の一つです。

継承とはそのクラスが持っているメンバを別のクラスに受け継がせることを
いいます。この時、元のクラスを基底クラス、受け継いだ方のクラスを
派生クラスといいます。

派生クラスでは継承したメンバは再定義せずに使うことができ、
さらに派生クラス内で新たに独自のメンバを定義することもできます。^^
また、基底クラスのことを親クラス、派生クラスのことを子クラスと
いうこともあります。

ここで、二つを親子とみなし、基底クラスのメンバを親が所有する家、家具と
すると、子どもが家と家具一式をすべて相続するのが継承といえます。

独自のメンバ定義は、新たに家具を増やすイメージでしょうか(^-^)
家を買って、全部自分で一から買い揃えるよりかはずっとお手軽です。

イマイチな例えかもしれませんが、これが継承のメリットです。

継承したモノを加工してみる?
基底クラスから継承したメンバ関数は、派生クラスで内容を再定義できます。
C++ではさらに、「派生クラスでメンバ関数を再定義すること」を前提とした
メンバ関数を定義できます。これを仮想関数といいます(^^)

また、純粋仮想関数というメンバ関数もあります。純粋仮想関数とは
クラスに呼び出し方だけが記述してあり、実体のない空のメンバ関数の
ことです。純粋仮想関数の中身は、派生クラスで再定義するときに
具体的な処理を書きます。

なぜこの様に面倒なことができる様になっているのでしょう(^^;)
時には、一般的なクラスで細かい所まで定義せず曖昧なまま進めたい事も
あるのです。純粋仮想関数はこんな時に使えるのです。

使いどころも含め、実に分かり難いので、次回以降でもっと詳しく
見ていきたいと思います。

今日の名言
過去を忘れ、他のことに一心に取り組む。これが私の悩み解決法である。
                           ジャック・デンプシー

済んだことは済んだことだ。過去を振り返らず、希望を持って新しい目標に向かうことだ。
                       ジョージ・C・マーシャル将軍

過ぎ去ったことは決して気にかけるな。これも経験の一つと考えて、悩みは忘れ去ろう。
目の前は常に困難だらけだ。振り返って過ぎ去った困難まで省みる必要はない。
                         ハーバート・フーヴァー

もし我々が、ただ手をこまねいて、家に閉じこもってくよくよ考えてばかりいれば、
ダーウィンのいわゆる「ウィバー・ギバー」なる卵をどっさり孵化させてしまう。
「ウィバー・ギバー」とは、人間の体を蝕み行動力と意志力を骨抜きにしてしまう。
時代遅れの幽霊にほかならぬ。
                           デール・カーネギー

2013年11月18日月曜日

C++ コピーコンストラクタ その2

前回、何気ないところですが、重要と書いた点の続きになります。(^_^;)
やはり賢いC++、デフォルトのコピーコンストラクタでもメンバ変数のコピーをしてくれます。
それでも、コピーコンストラクタを定義しなければいけない場合というのがあります。
メンバにポインタ変数が含まれる場合に、次のような問題が起こってしまうのです。
次のような例を見てください。

class Person {
public:
    Person() {
        m_pName = new(std::nothrow) char[32];
    }
    ~Person() {
        if (m_pName != NULL) {
            delete [] m_pName;
            m_pName = NULL;
        }
    }
            :    //このままコピーコンストラクタを用意しないでいると...   
private:
    char *m_pName;        //ここにポインタのメンバ変数があります
};

int main(void)
{
    Person *psn1 = new(std::nothrow) Person;
    //psn2 の初期化 デフォルトのコピーコンストラクタを呼び出します
    Person *psn2 = new(std::nothrow) Person(*psn1);
        :
    if (psn1 != NULL) {        delete psn1;
        psn1 = NULL;
    }
    if (psn2 != NULL) {
        delete psn2;        //2つ目のオブジェクトを削除しようとすると
        psn2 = NULL;      //実行時エラーが発生してしまいます(>_<)
    }
        :

実行例
# ./test
*** glibc detected *** ./test: double free or corruption (fasttop): 0x00728018 ***
中止

これは、デフォルトのコピーコンストラクタを使用したからなのですが、なぜ double free となってしまったのでしょうか?

実はpsn1オブジェクトの m_pName と psn2オブジェクトの m_pName のポインタが指し示す
先が同じだからです。
psn1オブジェクトを削除したときに、m_pNameの指し示す先のメモリ領域も削除されました。
そのため、psn2オブジェクトの m_pName が参照するエリアがなくなってしまい
プログラムが異常終了していたのです。

では、先ほどのサンプルにコピーコンストラクタを用意し、
エラー終了しないよう改造してみます。

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

class Person {
public:
    Person() {
        m_pName = new(std::nothrow) char[32];
    }
    Person(const Person &psn);  //コピーコンストラクタを宣言します
    ~Person() {
        if (m_pName != NULL) {
            delete [] m_pName;
            m_pName = NULL;
        }
    }
private:
    char *m_pName;
};

//コピーコンストラクタを定義します^^
Person::Person(const Person &psn)
{
    //人名は31文字までと勝手に決めています(^_^;)
    m_pName = new(std::nothrow) char[strnlen(psn.m_pName, 31)+1];
    strncpy(m_pName, psn.m_pName, strnlen(psn.m_pName, 32));
}

int main(void)
{
    Person *psn1 = new(std::nothrow) Person;
    //psn2 の初期化 定義したコピーコンストラクタを呼び出します
    Person *psn2 = new(std::nothrow) Person(*psn1);

    if (psn1 != NULL) {
        delete psn1;
        psn1 = NULL;
    }
    if (psn2 != NULL) {
        delete psn2;
        psn2 = NULL;
    }

    return 0;
}

ちなみに、このプログラム実行しても、何も表示しないで終了します。(^_^;)
正しく動作するようにはなりましたので、気が向いたらSetName, GetName関数
など追加して試してみてください。

今日の名言
偉大な心はしっかりしたよりどころを持っている。矮小な心は願望しか持っていない。
小さい心は不幸に慣れて大人しくなっている。偉大な心は不幸の上にそびえ立つ。
                                     ワシントン・アーヴィング

人間の偉大さは、不運に対してどのように耐えるかによって、決まるものだ。
                                     プルターク

熱中を得る方法は、自分の手がけている事柄を正しいと信じ、自分にはそれをやり遂げる
力があると信じ、積極的にそれをやり遂げたい気持ちになることである。昼のあとに夜が
くるように、ひとりでに熱中がやってくる。

何かを成し遂げようという気持ちがなければ、世間のどこへいっても頭角を現せない。
                                     デール・カーネギー

それが人生なのだ。A弦が切れることも、三本の弦で弾き終えることも。
                                ハリー・エマーソン・フォスディック

2013年11月13日水曜日

C#ではじめた Windows8 Application minority report

早いもので、もう先月の話になってしまったが

セミナー参加強化月間の締めとして

いろいろ使える! という

Microsoft Innovation Center(MIC)で 受講したセミナーが

ほんとに無料 !

C# の実務へ向けた取っ掛かりとして、思いのほか良かったので

その記録を今更ながら残しておく。

写真は、同じに見えるかもしれないが

こっそりとUI編と機能編で違いがある(^_^;)




ここで、どうでもいい話を一つ。

仕事では、まったくIDEを使わないので、Visual Studioで開発するとなると

あまりに便利すぎて、こんなに楽していいのだろうかと、いつも思う。

大枠はウィザードを実行するだけで出来上がるし、

Eclipseのコンテンツアシストと同様のコード補完機能も、

高速コーディングに大いに役立つ。

おかげで!? C# をやってる気が全くしない。

bashのタブキー補完もそうだが、考えた人はホントに天才だな...


このセミナー、 C# 普及のためとはいえ、絶好の機会であった。

ただ、Exerciseについての苦言を呈しておきたい(-_-;)

会場では資料に書いてある通りに進めればいいので

あまり躓くことなく、こなすことができる。

理解した気にもなれる。

しかし、せっかく自宅で復習しようとしても、

もらったCDに入っているプログラムを実行しようとすると

参照するデータベースファイルがないので、実行できない...

CDにTokyoSubwaysを追加しておいてくれないと、

スタンドアロンで確認できないではないかぁーっ(*_*;

実に残念である。

あと、Visual Studio Ultimateは全部入りみたいだけど

なぜ無料版のVisual Studio Express の方は、for XXX と分けてるのだろうか。

初め、色々あるからどれを使えばいいか、迷ったではないかぁーっ!


もちろん、これらはアンケートに忌憚なき意見として、書いておいた。


まとめ
MIC主催のセミナー 内容自体は分かりやすく、ためになるのでおススメ度はかなり高い。


さらに、土曜開催とかあるともっと有り難いのだが...

企画物のスタンプラリーもコンプリートし易くなるしって、違うか(^_^;)




2013年11月12日火曜日

C++ new/delete演算子の応用

オブジェクト以外も動的にメモリ確保ができます。^^
new演算子とdelete演算子を使って、int型やchar型などもメモリ確保と解放ができます。

int型のメモリ確保と解放
new演算子とdelete演算子を使ってint型のメモリを動的に確保/解放する例を示します。
C言語のmalloc()関数より、new演算子のほうが若干簡単な記述になっています。

new, deleteを使用
int *pNum = new(std::nothrow) int;    //メモリ確保できなかったらNULLを返すように
if (pNum != NULL) {                          //NULLでない事を確認して解放
    delete pNum;                              
    pNum = NULL;                            //未使用になったらNULL代入
}

malloc(), free()を使用
int *pNum = (int *)malloc(sizeof(int));
if (pNum != NULL) {                          //NULLでない事を確認して解放
    free(pNum);
    pNum = NULL;             //未使用になったらNULL代入
}

new, deleteの方のstd::nothrowは前回確認した例外を発生させずにNULLを
返すようにするための記述です。
また、malloc, free版にも共通している解放時のNULLチェックおよび解放後の
NULL代入は忘れずに書くクセをつけるとよいでしょう。(^^)


配列用のメモリ確保と解放
new演算子を使って、配列用のメモリ確保もできます。

int *pNum = new(std::nothrow) int[100];

[ ]の中に必要な要素数を記述します。この例ではint型のメモリ領域を
100個用意してみました。

次はnew演算子で確保した配列用のメモリ解放についてです。
これは配列名の前に [ ] を記述します。
もし、[ ] を忘れると配列の最初の要素しか解放されませんので要注意です。(^_^;)

delete [] pNum;   //このとき、要素数は記述しません


オブジェクトの配列のメモリ確保と解放
最後はオブジェクトの配列を確保/解放する場合についてです。
この場合も書き方は同じです。以下に例を示します。

PeachBox *pPeachBox = NULL;
pPeachBox = new(std::nothrow) PeachBox[24];
        :
if (pPeachBox != NULL) {
    delete [] pPeachBox;  //要素数は記述しませんので注意してください
    pPeachBox = NULL;
}

動的なメモリ確保のためのnew, deleteバリバリ使ってみてください。^^

今日の名言
どうすれば物事に熱中できるだろうか。まず自分の手がけている事柄のどんなところが
好きか自分に言い聞かせて、嫌いな部分は捨てて、さっさと好きな部分へ移ることだ、
それから夢中になって行動する-誰かに自分の好きな部分について聞かせる。
なぜそうした事に興味があるのか、教えてやる。
                                    デール・カーネギー

我々は自分が胸に温めてきた計画の廃墟を積み重ねて、天へ向かう。失敗だと思って
いたものが、実は成功だったということに気づきながら。
                            エイモス・ブロンソン・オルコット

苦さの味を知らぬ者は、甘さも分からない。
                                    ドイツの格言

困難とは作業衣を着た好機会にすぎない。
                                ヘンリー・J・カイザー

2013年11月4日月曜日

C++ フレンド

クラスのメンバをprivateにすると、当然他のクラスからアクセスできなくなります。
しかし、別の特定のクラスからほんのちょっとだけ特別にアクセスしたくなることが
あるかと思います。(^_^;)

そんな時に便利なのが、フレンドクラスの機能です。
たとえば、次のようにするとTheOtherInfoクラスは、OneInfoクラスのフレンドクラスと
なります。

//TheOtherInfoクラスをOneInfoクラスのフレンドクラスに宣言します^^
class OneInfo {
friend class TheOtherInfo;
private:
    int some_info;
};

こうすると、なんとTheOtherInfoクラスからOneInfoクラスのpriveteメンバに
アクセスできてしまうのです!

class TheOtherInfo {
public:
    void Accessor(OneInfo anyInfo) {
        //OneInfoクラスのprivateメンバにアクセス可!!
        anyInfo.some_info = 1;
    }
};

フレンドクラスの宣言は、クラス定義の中のどこに書いてもOKです。^^
また、今回の例では、TheOtherInfoクラスはOneInfoクラスのフレンドクラスとなります。
しかし、OneInfoクラスはTheOtherInfoクラスのフレンドクラスではありません。
悲しきかな、フレンドの関係は片方向だけになります。(>_<) そ、そんな...

また、以下のように特定の関数だけをフレンドの関係にすることもできます。

//クラス外にある通常の関数GlobalAccessor()をフレンドにします。
class OneInfo {
    friend void GlobalAccessor(OneInfo anyInfo);
        :

実はこのようにフレンドクラスやフレンド関数を使うと、privateで設定したアクセス制限が
破られてしまうので、後のプログラム修正が煩雑になってしまうというデメリットがあります。

フレンドクラスやフレンド関数の使用には十分に注意してください^^;

今日の名言
悩み事は次の三段階の解決策によって克服することだ。
  1. まず最悪の事態を考えてみる。
  2. どうしても避けられないと分かったら、あっさり覚悟を決める。
  3. ついで、気を落ち着けて、事態の改善に取りかかる。
                                   デール・カーネギー

人生は砂時計のようなものだ。砂時計の二つの瓶はごく細い首で繋がっていて、一度に
砂粒一つしか通り抜けられない。
これが人生の真の姿である。たとえ多忙きわまる日でも、仕事のいっぱい詰まった時間は、
一度にわずかずつ姿を現わす。人生はすべてこの通りである。たとえ一日中に取り組む仕事
問題、心の緊張はおびただしくても皆、必ず一度に一つずつやってくる。
                                ジェイムズ・ゴードン・ギルギー

忙しい状態に身を置くという単純なことで、なぜ不安を拭い去ることができるのだろうか?
そのわけは、ある法則 - 心理学が明らかにした最も基本的な法則のためである。
その法則とは、どんなに優秀な頭脳の持ち主であっても、人間は一度に「一つのこと」しか
思考できないというものだ。
                                       デール・カーネギー