2013年12月28日土曜日

C++ 純粋仮想関数




今回はオーバーライドにまつわるお話
其の参 です。(^-^)


純粋仮想関数とは、基底クラスで内容を
定義せずに派生クラスで関数の内容を
定義する関数です。

ややこしくなってしまった...


使いどころとしては、必ず継承して使うようなクラスの場合です。(^^;)
そのような場合は、基底クラスで仮想関数の内容を決められないからです。

class Food
{
public:
    //最初に virtual と書き、最後に = 0 と書く
    virtual void SetPrice(int price) = 0;
    int GetPrice(void);
protected:
    int m_price;
};

基底クラスでは、このように呼び出し方だけを記載しておきます。
注意する点は、純粋仮想関数を含むオブジェクトは生成できないということです。

間違ってオブジェクトを作ろうとすると、当然コンパイルエラーです(*´Д`)
そう、こんな風に...

test.cpp: In function ‘int main()’:
test.cpp:59:10: error: cannot declare variable ‘myFood’ to be of abstract type ‘Food’
test.cpp:6:7: note:   because the following virtual functions are pure within ‘Food’:
test.cpp:10:18: note:        virtual void Food::SetPrice(int)

それと、ひっそりとメンバ変数が protected に変わっています...
もし、private のままだと、勿論コンパイルエラーです(*´Д`)
派生クラスからアクセスできませんので当然です。
まぁ、こんな風に...

test.cpp: In member function ‘virtual void Vegetable::SetPrice(int)’:
test.cpp:14:9: error: ‘int Food::m_price’ is private
test.cpp:31:5: error: within this context
test.cpp: In member function ‘virtual void Meet::SetPrice(int)’:
test.cpp:14:9: error: ‘int Food::m_price’ is private
test.cpp:43:5: error: within this context

派生クラスでは、継承した純粋仮想関数をオーバーライドして
何をするかを定義します。

それでは、サンプルプログラムです。
#include <iostream>
#include <string.h>

using namespace std;

class Food
{
public:
    //純粋仮想関数
    virtual void SetPrice(int price) = 0;
    int GetPrice(void);
protected:  //protectedにしておかないと、継承先で参照できない
    int m_price;
};

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

//派生クラスVegetable
class Vegetable : public Food
{
public:
    void SetPrice(int price);
};

void Vegetable::SetPrice(int price)
{
    m_price = price * 2;
}

//派生クラスMeet
class Meet : public Food
{
public:
    void SetPrice(int price);
};

void Meet::SetPrice(int price)
{
    m_price = price / 2;
}

int main(void)
{
    Food *pFood;
    Vegetable myVegetable;
    Meet myMeet;

    pFood = &myVegetable;
    pFood->SetPrice(500);    //VegetableクラスのSetPrice()を呼び出す
    cout << "Vegetable Price = " << pFood->GetPrice() << endl;
    pFood = &myMeet;
    pFood->SetPrice(1500);    //MeetクラスのSetPrice()を呼び出す
    cout << "Meet Price = " << pFood->GetPrice() << endl;

    return 0;
}

実行結果
# ./test
Vegetable Price = 1000
Meet Price = 750

ハマる楽しさオーバーライド これもC++のいいところです(^^)

今日の名言
不眠症で眠れないのは、不眠症を気にするからだ。
なぜ気になるかといえば、眠らないからだ。
                     フランクリン・ピアース・アダムス

忍耐はどんな悩みにも効く名薬である。
                     プラウトゥス

私は貧乏と病気のどん底を生き抜いてきました。「あらゆる人に振りかかる
悩みをあなたはどうやって切り抜けてきたのですか」と尋ねる人があれば、
私はいつもこう答えます。「私は昨日耐えました。今日も耐えることができます。
そして明日のことは決して考えないようにしています」
                     ドロシー・ディックス