Yamamoto's Laboratory
 
 
クラス
クラスの例
 
ライブラリー
 
 

クラスとは

クラスは,C++の最も重要な機能です.それは,構造体(C言語では,struct)とよく似ています.構造体を用いると,データを階層的に管理でき,わかりやすいプログラムになります.クラスは,この構造体の機能に加えて,データを操作する関数(メンバー関数)も含ませることができます.このようにデータとそれを操作する関数をひとかたまりにすることが,クラスにより可能になります.そこのとにより,わかりやすくまとまったプログラムを作ることが可能になります.

単純なクラスの例

クラスは便利だ

最も単純なクラスの定義は,次のようにします.

class class_name{
// 非公開の変数定義と関数のプロトタイプ
public:
// 公開の変数定義と関数のプロトタイプ
}object_list;

通常,object_listは,書きません.プログラム中で後から宣言できるからです.

クラスの例をリスト1に示します.これは,二次関数(f(x)=ax2+bx+c)の係数を設定して,関数とその導関数の値を計算するクラスの例です.リスト1の007—027がクラスの定義です.

クラスの例(simple_class.cpp).

001   #include <iostream>
002   using namespace std;
003   
004   //============================================================
005   // class
006   //============================================================
007   class func2{
008     double a, b, c;
009   public:
010     void set(double in_a, double in_b, double in_c);
011     double value(double x);
012     double dvalue(double x);
013   };
014   
015   void func2::set(double in_a, double in_b, double in_c){
016     a = in_a;
017     b = in_b;
018     c = in_c;
019   }
020   
021   double func2::value(double x){
022     return (a*x+b)*x+c;
023   }
024   
025   double func2::dvalue(double x){
026     return a*x+b;
027   }
028   
029   
030   //============================================================
031   // main function
032   //============================================================
033   int main(){
034     func2 f;
035     double x=2.3;
036   
037     f.set(1.0, 2.0, 3.0);
038     cout << "f(" << x << ") =     " << f.value(x) << endl;
039     cout << "df/dx(" << x << ") = " << f.dvalue(x) << endl;
040   
041     return 0;
042   }

同じようなことが,C言語を使っても可能です(例:global.carg.c).しかも,C言語の方がソースプログラムは短く,一見,優れているように感じるかもしれません.しかし,C言語では,二次関数の係数の渡し方が問題になります.係数をグローバル変数(例:global.c)で渡したり,関数の引数(arg.c)に含めたりします.グローバル変数にすると,複数の二次関数が必要な場合,それに応じた数の変数と関数が必要になります.10個の二次関数が必要な場合,30個の変数と10個の関数が必要!! これはまったくナンセンスです.一方,引数を使うと,そのような問題は無くなります.しかし,引数並びに係数(a, b, c)と変数(x)が同列に並ぶので,プログラムが見苦しくなります.さらに,引数が多くなる分,バグが入り込む余地も増えます.その一方で,C++の場合,関数とデータがひとつのクラス内に記述できますので,C言語での問題点は無くなります.

ここで示した簡単な例から,簡単なプログラムであればC言語の方が,ソースが短くて,優れているかもしれません.しかし,少しプログラムが複雑になると,C++のほうが優れていることが多いです.クラスを使うと,そのオブジェクトに関数と変数が同時にメモリーに記憶されるの便利です.C言語では,関数がプログラムの主な役割を果たす.C++では,クラスを使うことによりその関数の機能を拡張できます.

コンストラクター

先の例では,オブジェクトを作成した時点で,その機能は決まります.あとで,係数を入れるのは面倒であるとともに,美しくありません.そこで,リスト2のようにすると,オブジェクトの生成と同時に,係数の設定ができます.

コンストラクタを使った例(constructor.cpp).

001   #include <iostream>
002   using namespace std;
003   
004   //============================================================
005   // class
006   //============================================================
007   class func2{
008     double a, b, c;
009   public:
010     func2(double in_a=0, double in_b=0, double in_c=0);
011     double value(double x);
012     double dvalue(double x);
013   };
014   
015   func2::func2(double in_a, double in_b, double in_c){
016     a = in_a;
017     b = in_b;
018     c = in_c;
019   }
020   
021   double func2::value(double x){
022     return (a*x+b)*x+c;
023   }
024   
025   double func2::dvalue(double x){
026     return a*x+b;
027   }
028   
029   
030   //============================================================
031   // main function
032   //============================================================
033   int main(){
034     func2 f(1.0, 2.0, 3.0);
035     double x=2.3;
036   
037     cout << "f(" << x << ") =     " << f.value(x) << endl;
038     cout << "df/dx(" << x << ") = " << f.dvalue(x) << endl;
039   
040     return 0;
041   }

クラス名と同じ関数名がコンストラクターになります.オブジェクト生成時に,このコンストラクター関数が実行されます.コンストラクターには戻り値がありません.そのため,戻り値の型指定を行いません.さらに,void型の指定も行いません.ここでは,オブジェクト生成時に引数を指定しないと,デフォルトの値(a=0, b=0, c=0)になります.

演算子のオーバーロード

先のプログラムで,最もみっともないのは,関数の値を得るために,f.value(x)としているところです.できれば,f(x)としたいところです.C++では,演算子のオーバーロードを使うと,その機能が実現できます.具体的には,リスト3のようにします.

演算子のオーバーロードを使った例(operator.cpp).

001   #include <iostream>
002   using namespace std;
003   
004   //============================================================
005   // class
006   //============================================================
007   class func2{
008     double a, b, c;
009   public:
010     func2(double in_a=0, double in_b=0, double in_c=0);
011     double operator()(double x);
012     double dvalue(double x);
013   };
014   
015   func2::func2(double in_a, double in_b, double in_c){
016     a = in_a;
017     b = in_b;
018     c = in_c;
019   }
020   
021   double func2::operator()(double x){
022     return (a*x+b)*x+c;
023   }
024   
025   double func2::dvalue(double x){
026     return a*x+b;
027   }
028   
029   
030   //============================================================
031   // main function
032   //============================================================
033   int main(){
034     func2 f(1.0, 2.0, 3.0);
035     double x=2.3;
036   
037     cout << "f(" << x << ") =     " << f(x) << endl;
038     cout << "df/dx(" << x << ") = " << f.dvalue(x) << endl;
039   
040     return 0;
041   }

演算子のオーバーロードと難しそうな名前がついていますが,実態は極めて単純です.「operator()」が関数名となっていると考えれば,通常の関数と殆ど変わりません.ただし,ドット演算子やアロー演算子を使わずに関数(演算子)が呼び出せます.

導関数



no counter