2014年1月の記事一覧

OpenFOAM学習者向け C++プログラミング基礎 - クラス、テンプレートクラス

http://eddy.pu-toyama.ac.jp/bbx440ueh-126/#_126
上記にアップデート版を作成しました。(2019/01/06)
----

OpenFOAM 学習者向けのC++プログラミング基礎 学習資料を作成しました。
興味ある方は、ご覧ください。コンパイルして、試してください。
ご意見、ご感想、質問など、大歓迎です。掲示板に返信してください。
例題が陳腐です。良いアイデアがあれば、ぜひ、教えて下さい。

----

今回の目的:
 クラス の基本について学ぶ。
 テンプレート クラス の基本について学ぶ。

基本方針:
 main はできるだけシンプルにしていく。


 ごく基本的なプログラム例を CODE 1 に示す。
 このプログラムでは,キーボードから整数を入力し,その値の2倍を画面に表示する。

CODE 1
#include <iostream>

int main()
{
    int n;
    std::cout << "整数を入力してください。" << std::endl;
    std::cin >> n;
    std::cout << "整数 " << n << " の2倍は " << n + n << " です。" << std::endl; 

     return 0;
}


 整数(int)型を発展させて,その値を2倍にする機能のある整数型を作り出すとする。
 この機能をクラスとして実装する。クラス名を extendedInt とする。

CODE 2
#include <iostream>
    
// クラスの定義 スタート
class extendedInt
{
    int n_;
    
    public:
    
        int makeDouble(const int& n)
        {
            return n + n ;
        };
};
// クラスの定義 ここまで
    
int main()
{
    int n;
    extendedInt extInt;
   
    std::cout << "整数を入力してください。" << std::endl;
    std::cin >> n;
    std::cout << "整数 " << n << " の2倍は " << extInt.makeDouble(n) << " です。" << std::endl; 

    return 0;
}
 
 
 クラスに整数を受け取るコンストラクタを作成する。
 画面表示部分もクラスに任せることにする。
 

CODE 3
    #include <iostream>
    
    class extendedInt
    {
        int n_;
    
    public:
    
        // constructor
        extendedInt(const int& n )
        {
            n_ = n;
        };
    
        int makeDouble(const int& n)
        {
            return n + n;
        };
    
        bool calcAndDisplay()
        {
            std::cout << "整数 " << n_ << " の2倍は " << makeDouble(n_) << " です。" << std::endl; 
        };
    };
    
    int main()
    {
        int n;
    
        std::cout << "整数を入力してください。" << std::endl;
        std::cin >> n;
    
        extendedInt extInt(n); 
        extInt.calcAndDisplay();
    
        return 0;
    }


 整数を与える部分もクラスに任せてみる。

CODE 4
    #include <iostream>
    
    class extendedInt
    {
        int n_;
    
    public:
    
        int makeDouble(const int& n)
        {
            return n + n;
        };
    
        bool calcAndDisplay()
        {
            std::cout << "整数 " << n_ << " の2倍は " << makeDouble(n_) << " です。" << std::endl; 
        };
    
        bool read()
        {
            std::cout << "整数を入力してください。" << std::endl;
            std::cin >> n_;
        };
        
    };
    
    int main()
    {
        extendedInt extInt;
    
        extInt.read();
        extInt.calcAndDisplay();
    
        return 0;
    }


 整数と同じようなものを、実数でも実現したいとする。
 単純に考えると、整数用と実数用の2つのクラスを作るかも。

CODE 5
    #include <iostream>
   
    // 整数専用クラス
    class extendedInt
    {
        int n_;
    
    public:
    
        int makeDouble(const int& n)
        {
            return n + n;
        };
    
        bool calcAndDisplay()
        {
            std::cout << "整数 " << n_ << " の2倍は " << makeDouble(n_) << " です。" << std::endl; 
        };
    
        bool read()
        {
            std::cout << "整数を入力してください。" << std::endl;
            std::cin >> n_;
        };
    };
   
    // 実数専用クラス
    class extendedFloat
    {
        float f_;
    
    public:
    
        float makeDouble(const float& f)
        {
            return f + f;
        };
    
        bool calcAndDisplay()
        {
            std::cout << "実数 " << f_ << " の2倍は " << makeDouble(f_) << " です。" << std::endl; 
        };
    
        bool read()
        {
            std::cout << "実数を入力してください。" << std::endl;
            std::cin >> f_;
        };
    };
    
    int main()
    {
        extendedInt extInt;
        extInt.read();
        extInt.calcAndDisplay();
    
    
        extendedFloat extFlt;
        extFlt.read();
        extFlt.calcAndDisplay();
    
        return 0;
    }


 ほとんど同じことを書いたクラスが2つ。内部に持つ型が異なるだけ。
 まとめられないの?templateを使ってまとめましょう。
 先ほどの2つのクラスで,int または float だったところを,Type と名前をつけたテンプレートクラスで宣言します。クラスの定義内で,Type となっている部分は,mainから呼び出す際に定めたクラスとなります。

CODE 6
    #include <iostream>
    #include <string>
    
    template<class Type>
    class extendedType
    {
        Type x_;
        std::string type_;
    
    public:
    
        extendedType(const std::string& type)
        {
            type_=type;
        }
    
        Type makeDouble(const Type& x)
        {
            return x + x;
        };
    
        bool calcAndDisplay()
        {
            std::cout << type_ << x_ << " の2倍は " << makeDouble(x_) << " です。" << std::endl; 
        };
    
        bool read()
        {
            std::cout << type_ << " を入力してください。" << std::endl;
            std::cin >> x_;
        };
    };
    
    
    int main()
    {
        extendedType<int> extInt("整数");
    
        extInt.read();
        extInt.calcAndDisplay();
    
    
        extendedType<float> extFlt("実数");
    
        extFlt.read();
        extFlt.calcAndDisplay();
    
        return 0;
    }


 コンストラクタを作成しました。クラスからオブジェクト(インスタンス)を作る時に、型の名前を渡すようにしました。
 mainでの宣言部分に注意してください。宣言時に、クラス側のtemplateが決定されます。

 これで、色々な型に対応できます。
 文字列型にも。ただし、演算子+が使える必要があります。


CODE 7
    #include <iostream>
    #include <string>
    
    template<class Type>
    class extendedType
    {
    private:
        Type x_;
        std::string type_;
    
    public:
    
        extendedType(const std::string& type)
        {
            type_=type;
        }
    
        bool calcAndDisplay()
        {
            std::cout << type_ << x_ << " の2倍は " << makeDouble(x_) << " です。" << std::endl; 
        };
    
        bool read()
        {
            std::cout << type_ << " を入力してください。" << std::endl;
            std::cin >> x_;
        };
    
    private:
        Type makeDouble(const Type& x)
        {
            return x + x;  
        };
    };
    
    
    int main()
    {
        extendedType<int> extInt("整数");
        extInt.read();
        extInt.calcAndDisplay();
    
        extendedType<float> extFlt("実数");
        extFlt.read();
        extFlt.calcAndDisplay();
    
        extendedType<std::string> extStr("文字列");
        extStr.read();
        extStr.calcAndDisplay();
    
        return 0;
    }
0